├── .circleci └── config.yml ├── .editorconfig ├── .eslintrc.js ├── .git2gus └── config.json ├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE │ ├── Bug_report.md │ └── Feature_request.md ├── PULL_REQUEST_TEMPLATE.md ├── dependabot.yml ├── no-response.yml └── workflows │ └── slackprnotification.yml ├── .gitignore ├── .images └── vscodeScreenshot.png ├── .lintstagedrc.js ├── .mocharc.json ├── .nycrc ├── .prettierrc.json ├── .vscode ├── launch.json ├── settings.json └── tasks.json ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── LICENSE.txt ├── README.md ├── SECURITY.md ├── STRATEGY.md ├── bin ├── dev ├── dev.cmd ├── run └── run.cmd ├── commitlint.config.js ├── messages ├── config.get.md ├── config.list.md ├── config.set.md ├── config.unset.md ├── env.alias.set.md ├── env.alias.unset.md ├── env.connect.md ├── env.create.compute.md ├── env.create.org.md ├── env.delete.md ├── env.display.md ├── env.list.md ├── env.log.get.md ├── env.log.list.md ├── env.log.tail.md ├── env.logdrain.add.md ├── env.logdrain.list.md ├── env.logdrain.remove.md ├── env.open.md ├── env.usage.md ├── env.var.get.md ├── env.var.list.md ├── env.var.set.md ├── env.var.unset.md ├── generate.analytics.template.md ├── generate.apex.class.md ├── generate.apex.test.md ├── generate.apex.trigger.md ├── generate.community.md ├── generate.function.md ├── generate.lightning.component.md ├── generate.lightning.event.md ├── generate.lightning.interface.md ├── generate.project.md ├── login.md ├── login.org.jwt.md ├── login.org.md ├── logout.md ├── logout.org.md ├── messages.json ├── org.json ├── project.deploy.functions.md ├── project.deploy.md ├── project.deploy.org.md ├── project.retrieve.md ├── project.retrieve.org.md ├── run.apex.md ├── run.function.md ├── run.function.start.md ├── test.apex.md ├── test.function.md ├── usage.md └── whoami.md ├── package.json ├── src ├── commands │ ├── config │ │ ├── get.ts │ │ ├── list.ts │ │ ├── set.ts │ │ └── unset.ts │ ├── data │ │ └── data.ts │ ├── env │ │ ├── alias │ │ │ ├── set.ts │ │ │ └── unset.ts │ │ ├── connect.ts │ │ ├── create │ │ │ ├── compute.ts │ │ │ └── org.ts │ │ ├── delete.ts │ │ ├── display.ts │ │ ├── list.ts │ │ ├── log │ │ │ ├── get.ts │ │ │ ├── list.ts │ │ │ └── tail.ts │ │ ├── logdrain │ │ │ ├── add.ts │ │ │ ├── list.ts │ │ │ └── remove.ts │ │ ├── open.ts │ │ ├── usage.ts │ │ └── var │ │ │ ├── get.ts │ │ │ ├── list.ts │ │ │ ├── set.ts │ │ │ └── unset.ts │ ├── event │ │ └── event.ts │ ├── generate │ │ ├── analytics │ │ │ └── template.ts │ │ ├── apex │ │ │ ├── class.ts │ │ │ ├── test.ts │ │ │ └── trigger.ts │ │ ├── community.ts │ │ ├── function.ts │ │ ├── lightning │ │ │ ├── component.ts │ │ │ ├── event.ts │ │ │ └── interface.ts │ │ └── project.ts │ ├── heroku │ │ └── heroku.ts │ ├── login.ts │ ├── login │ │ ├── functions.ts │ │ ├── org.ts │ │ └── org │ │ │ └── jwt.ts │ ├── logout.ts │ ├── logout │ │ └── org.ts │ ├── package │ │ └── package.ts │ ├── project │ │ ├── deploy.ts │ │ ├── deploy │ │ │ ├── functions.ts │ │ │ └── org.ts │ │ ├── retrieve.ts │ │ └── retrieve │ │ │ └── org.ts │ ├── reset.ts │ ├── run │ │ ├── apex.ts │ │ ├── function.ts │ │ └── function │ │ │ └── start.ts │ ├── test │ │ ├── apex.ts │ │ └── function.ts │ ├── usage.ts │ └── whoami.ts ├── configs │ ├── account.ts │ ├── aliases.ts │ ├── constants.ts │ └── environments.ts ├── hooks │ └── readme.ts ├── index.ts ├── project │ ├── deployer.ts │ ├── functions-deployer.ts │ ├── index.ts │ └── sf-deployer.ts ├── sf-command.ts └── utils.ts ├── test ├── .eslintrc.js ├── commands │ └── noop.test.ts └── tsconfig.json ├── tsconfig.json └── yarn.lock /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | --- 2 | version: 2.1 3 | orbs: 4 | release-management: salesforce/npm-release-management@4 5 | 6 | workflows: 7 | version: 2 8 | test-and-release: 9 | jobs: 10 | - release-management/test-package: 11 | name: node-latest 12 | node_version: latest 13 | - release-management/test-package: 14 | name: node-12 15 | - release-management/release-package: 16 | github-release: true 17 | requires: 18 | - node-latest 19 | filters: 20 | branches: 21 | only: main 22 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | 10 | [*.md] 11 | trim_trailing_whitespace = false 12 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | module.exports = { 8 | extends: ['eslint-config-salesforce-typescript', 'eslint-config-salesforce-license'], 9 | rules: { 10 | '@typescript-eslint/require-await': 0, 11 | 'no-console': 0, // Demo cli, allow console logs 12 | }, 13 | }; 14 | -------------------------------------------------------------------------------- /.git2gus/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "productTag": "a1aB00000004Bx8IAE", 3 | "defaultBuild": "offcore.tooling.52" 4 | } -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # These owners will be the default owners for everything in 2 | # the repo. Unless a later match takes precedence, 3 | # @forcedotcom/pdt will be requested for 4 | # review when someone opens a pull request. 5 | * @forcedotcom/pdt 6 | #ECCN:Open Source -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | --- 5 | 6 | 9 | 10 | 13 | 14 | ### Summary 15 | 16 | _Short summary of what is going on or to provide context_. 17 | 18 | ### Steps To Reproduce: 19 | 20 | 1. This is step 1. 21 | 1. This is step 2. All steps should start with '1.' 22 | 23 | ### Expected result 24 | 25 | _Describe what should have happened_. 26 | 27 | ### Actual result 28 | 29 | _Describe what actually happened instead_. 30 | 31 | ### Additional information 32 | 33 | _Feel free to attach a screenshot_. 34 | 35 | **VS Code Version**: 36 | 37 | **SFDX CLI Version**: 38 | 39 | **OS and version**: 40 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | --- 5 | 6 | **Is your feature request related to a problem? Please describe.** 7 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 8 | 9 | **Describe the solution you'd like** 10 | A clear and concise description of what you want to happen. 11 | 12 | **Describe alternatives you've considered** 13 | A clear and concise description of any alternative solutions or features you've considered. 14 | 15 | **Additional context** 16 | Add any other context or screenshots about the feature request here. 17 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### What does this PR do? 2 | 3 | ### What issues does this PR fix or reference? 4 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "npm" 4 | directory: "/" 5 | schedule: 6 | interval: "monthly" 7 | labels: 8 | - "dependencies" 9 | open-pull-requests-limit: 100 10 | pull-request-branch-name: 11 | separator: "-" 12 | ignore: 13 | - dependency-name: "typescript" 14 | - dependency-name: "sinon" 15 | - dependency-name: "string-ansi" 16 | - dependency-name: "*" 17 | update-types: ["version-update:semver-major"] 18 | -------------------------------------------------------------------------------- /.github/no-response.yml: -------------------------------------------------------------------------------- 1 | # Configuration for probot-no-response - https://github.com/probot/no-response 2 | 3 | daysUntilClose: 7 4 | responseRequiredLabel: 'more information required' 5 | closeComment: > 6 | This issue has been automatically closed because there has been no response 7 | to our request for more information from the original author. Currently, there 8 | is not enough information provided for us to take action. Please reply and 9 | reopen this issue if you need additional assistance. 10 | -------------------------------------------------------------------------------- /.github/workflows/slackprnotification.yml: -------------------------------------------------------------------------------- 1 | name: Slack pull request open notification 2 | 3 | on: 4 | pull_request: 5 | types: [opened, reopened] 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Notify slack pr open 12 | env: 13 | WEBHOOK_URL : ${{ secrets.CLI_TEAM_SLACK_WEBHOOK_URL }} 14 | PULL_REQUEST_AUTHOR_ICON_URL : ${{ github.event.pull_request.user.avatar_url }} 15 | PULL_REQUEST_AUTHOR_NAME : ${{ github.event.pull_request.user.login }} 16 | PULL_REQUEST_AUTHOR_PROFILE_URL: ${{ github.event.pull_request.user.html_url }} 17 | PULL_REQUEST_BASE_BRANCH_NAME : ${{ github.event.pull_request.base.ref }} 18 | PULL_REQUEST_COMPARE_BRANCH_NAME : ${{ github.event.pull_request.head.ref }} 19 | PULL_REQUEST_NUMBER : ${{ github.event.pull_request.number }} 20 | PULL_REQUEST_REPO: ${{ github.event.pull_request.head.repo.name }} 21 | PULL_REQUEST_TITLE : ${{ github.event.pull_request.title }} 22 | PULL_REQUEST_URL : ${{ github.event.pull_request.html_url }} 23 | uses: salesforcecli/pr-notification-action@main 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # -- CLEAN 2 | 3 | # use yarn by default, so ignore npm 4 | package-lock.json 5 | 6 | # never checkin npm config 7 | .npmrc 8 | 9 | # debug logs 10 | npm-error.log 11 | yarn-error.log 12 | lerna-debug.log 13 | 14 | # compile source 15 | lib 16 | 17 | # test artifacts 18 | *xunit.xml 19 | *checkstyle.xml 20 | *unitcoverage 21 | .nyc_output 22 | coverage 23 | 24 | # generated docs 25 | docs 26 | 27 | # -- CLEAN ALL 28 | node_modules 29 | 30 | # -- 31 | # put files here you don't want cleaned with sf-clean 32 | 33 | # os specific files 34 | .DS_Store 35 | .idea 36 | 37 | # oclif 38 | oclif.manifest.json -------------------------------------------------------------------------------- /.images/vscodeScreenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/salesforcecli/CLI-Unification-demo/c356f76c8f900afe8e07f26c494d5e457092ba38/.images/vscodeScreenshot.png -------------------------------------------------------------------------------- /.lintstagedrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | '**/*.{js,json,md}?(x)': () => 'npm run reformat' 3 | }; 4 | -------------------------------------------------------------------------------- /.mocharc.json: -------------------------------------------------------------------------------- 1 | { 2 | "require": "ts-node/register,source-map-support/register", 3 | "watch-extensions": "ts", 4 | "recursive": true, 5 | "reporter": "spec", 6 | "timeout": 5000, 7 | "ignore": "node_modules/**/*" 8 | } 9 | -------------------------------------------------------------------------------- /.nycrc: -------------------------------------------------------------------------------- 1 | { 2 | "nyc": { 3 | "extends": "@salesforce/dev-config/nyc" 4 | } 5 | } -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | "@salesforce/prettier-config" 2 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "pwa-node", 9 | "request": "attach", 10 | "name": "Attach", 11 | "port": 9229, 12 | "skipFiles": ["/**"], 13 | "smartStep": true 14 | }, 15 | { 16 | "name": "Run All Tests", 17 | "type": "node", 18 | "request": "launch", 19 | "protocol": "inspector", 20 | "program": "${workspaceFolder}/node_modules/mocha/bin/_mocha", 21 | "args": ["--inspect", "--no-timeouts", "--colors", "test/**/*.test.ts"], 22 | "env": { 23 | "NODE_ENV": "development", 24 | "SFDX_ENV": "development" 25 | }, 26 | "sourceMaps": true, 27 | "smartStep": true, 28 | "internalConsoleOptions": "openOnSessionStart", 29 | "preLaunchTask": "Compile" 30 | }, 31 | { 32 | "type": "pwa-node", 33 | "request": "launch", 34 | "name": "Run command", 35 | "program": "./bin/dev", 36 | "args": ["env", "list"], 37 | "env": { 38 | "NODE_ENV": "development", 39 | "SFDX_ENV": "development" 40 | }, 41 | "sourceMaps": true, 42 | "smartStep": true, 43 | "internalConsoleOptions": "openOnSessionStart" 44 | } 45 | ] 46 | } 47 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.exclude": { 3 | "**/.git": true, 4 | "**/.svn": true, 5 | "**/.hg": true, 6 | "**/CVS": true, 7 | "**/.DS_Store": true 8 | }, 9 | "search.exclude": { 10 | "**/lib": true, 11 | "**/bin": true 12 | }, 13 | "editor.tabSize": 2, 14 | "editor.formatOnSave": true, 15 | "rewrap.wrappingColumn": 80 16 | } 17 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "problemMatcher": "$tsc-watch", 4 | "tasks": [ 5 | { 6 | "label": "Compile", 7 | "group": { 8 | "kind": "build", 9 | "isDefault": true 10 | }, 11 | "command": "yarn", 12 | "type": "shell", 13 | "presentation": { 14 | "focus": false, 15 | "panel": "dedicated" 16 | }, 17 | "args": ["run", "prepack"], 18 | "isBackground": false, 19 | "problemMatcher": { 20 | "owner": "typescript", 21 | "fileLocation": "relative", 22 | "pattern": { 23 | "regexp": "^(.*\\.ts):(\\d*):(\\d*)(\\s*-\\s*)(error|warning|info)\\s*(TS\\d*):\\s*(.*)$", 24 | "file": 1, 25 | "line": 2, 26 | "column": 3, 27 | "severity": 5, 28 | "code": 6, 29 | "message": 7 30 | } 31 | } 32 | }, 33 | { 34 | "label": "Lint", 35 | "command": "yarn", 36 | "type": "shell", 37 | "presentation": { 38 | "focus": false, 39 | "panel": "dedicated" 40 | }, 41 | "args": ["run", "lint"], 42 | "isBackground": false, 43 | "problemMatcher": { 44 | "owner": "typescript", 45 | "fileLocation": "relative", 46 | "pattern": { 47 | "regexp": "^(ERROR|WARNING|INFO):\\s*(.*\\.ts):(\\d*):(\\d*)(\\s*-\\s*)(.*)$", 48 | "file": 2, 49 | "line": 3, 50 | "column": 4, 51 | "severity": 1, 52 | "message": 6 53 | } 54 | } 55 | } 56 | ] 57 | } 58 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. 4 | 5 | ### [1.6.7](https://github.com/salesforcecli/cli-taxonomy-experiment/compare/v1.6.6...v1.6.7) (2021-10-12) 6 | 7 | ### [1.6.6](https://github.com/salesforcecli/cli-taxonomy-experiment/compare/v1.6.5...v1.6.6) (2021-06-22) 8 | 9 | 10 | ### Bug Fixes 11 | 12 | * change "sf help" to "sf --help" in readme ([5c1a132](https://github.com/salesforcecli/cli-taxonomy-experiment/commit/5c1a1321b18080f3bb8f59a48e206e8765b2e420)) 13 | 14 | ### [1.6.5](https://github.com/salesforcecli/cli-taxonomy-experiment/compare/v1.6.4...v1.6.5) (2021-06-22) 15 | 16 | 17 | ### Bug Fixes 18 | 19 | * edit login functions help ([6e05f0b](https://github.com/salesforcecli/cli-taxonomy-experiment/commit/6e05f0b84b3638cff83eccc2c2a1245ecd46f51d)) 20 | 21 | ### [1.6.4](https://github.com/salesforcecli/cli-taxonomy-experiment/compare/v1.6.3...v1.6.4) (2021-06-22) 22 | 23 | 24 | ### Bug Fixes 25 | 26 | * add all subtopics to package.json ([f0f8b96](https://github.com/salesforcecli/cli-taxonomy-experiment/commit/f0f8b96024eacfc8fc76a8d1b8b551ef3b241e78)) 27 | 28 | ### [1.6.3](https://github.com/salesforcecli/cli-taxonomy-experiment/compare/v1.6.2...v1.6.3) (2021-06-22) 29 | 30 | 31 | ### Bug Fixes 32 | 33 | * don't ship oclif.manifest.json with package ([d0af8c9](https://github.com/salesforcecli/cli-taxonomy-experiment/commit/d0af8c9521eb82a0f29bd6c5bb9739df080cf080)) 34 | * update cli-ux tables ([44b1158](https://github.com/salesforcecli/cli-taxonomy-experiment/commit/44b1158a2a48e08b5cc9d8a8735169145fdf9f84)) 35 | 36 | ### [1.6.3](https://github.com/salesforcecli/cli-taxonomy-experiment/compare/v1.6.2...v1.6.3) (2021-06-22) 37 | 38 | ### Bug Fixes 39 | 40 | - don't ship oclif.manifest.json with package ([d0af8c9](https://github.com/salesforcecli/cli-taxonomy-experiment/commit/d0af8c9521eb82a0f29bd6c5bb9739df080cf080)) 41 | 42 | ### [1.6.2](https://github.com/salesforcecli/cli-taxonomy-experiment/compare/v1.6.1...v1.6.2) (2021-06-22) 43 | 44 | ### Bug Fixes 45 | 46 | - add a few more topic descriptions to package.json ([27864bf](https://github.com/salesforcecli/cli-taxonomy-experiment/commit/27864bfceed1cd752c08c8240cfa32bd9e06124e)) 47 | 48 | ### [1.6.1](https://github.com/salesforcecli/cli-taxonomy-experiment/compare/v1.6.0...v1.6.1) (2021-06-22) 49 | 50 | ### Bug Fixes 51 | 52 | - ensure top level commands have descriptions ([1da332f](https://github.com/salesforcecli/cli-taxonomy-experiment/commit/1da332f3afa94960559893a191318dcb6d4e4f17)) 53 | 54 | ## [1.6.0](https://github.com/salesforcecli/cli-taxonomy-experiment/compare/v1.5.1...v1.6.0) (2021-06-22) 55 | 56 | ### Features 57 | 58 | - hook up help for run and test commands ([1d23842](https://github.com/salesforcecli/cli-taxonomy-experiment/commit/1d23842e4d0e88ec9354b72fa96d3cdb5f1a3a6b)) 59 | - hook up help md to env commands ([0fec437](https://github.com/salesforcecli/cli-taxonomy-experiment/commit/0fec437fcb358270a601cdefb9c3e46b1ebcd488)) 60 | - hook up help to login and logout commands ([bd3f1e2](https://github.com/salesforcecli/cli-taxonomy-experiment/commit/bd3f1e279a84e95a63ede3f2414a37c25533f9da)) 61 | - hookup help for usage and whoami commands ([d94c2b0](https://github.com/salesforcecli/cli-taxonomy-experiment/commit/d94c2b0dfe2fc2003097deeaa87eb17b1b794f2f)) 62 | - hookup help md to generate commands ([4299e1f](https://github.com/salesforcecli/cli-taxonomy-experiment/commit/4299e1fb6604e8841cd1efa9d6395cd8666cca3c)) 63 | - tie help messages to command for config ([0fbcdb2](https://github.com/salesforcecli/cli-taxonomy-experiment/commit/0fbcdb257b0e05deb23f660a2f72142b694f7b8d)) 64 | 65 | ### Bug Fixes 66 | 67 | - add project retrieve ([f40a27e](https://github.com/salesforcecli/cli-taxonomy-experiment/commit/f40a27e1955d2808fb53646f816dd36c06da7f92)) 68 | - put retrieve under project topic ([4d5d3e3](https://github.com/salesforcecli/cli-taxonomy-experiment/commit/4d5d3e3fcdda36861478e1b30a71e113169df5b1)) 69 | 70 | ### [1.5.1](https://github.com/salesforcecli/cli-taxonomy-experiment/compare/v1.5.0...v1.5.1) (2021-06-21) 71 | 72 | ## [1.5.0](https://github.com/salesforcecli/cli-taxonomy-experiment/compare/v1.4.2...v1.5.0) (2021-06-21) 73 | 74 | ### Features 75 | 76 | - update help example ([f6e49c8](https://github.com/salesforcecli/cli-taxonomy-experiment/commit/f6e49c8e76816ec6f341a98d9ff90e21510bbc58)) 77 | - update to latest commands for tdx demo ([051bdc4](https://github.com/salesforcecli/cli-taxonomy-experiment/commit/051bdc4a8901bc1db998eab6f4538bad552bb9e7)) 78 | - update to md help ([c33ec9d](https://github.com/salesforcecli/cli-taxonomy-experiment/commit/c33ec9d73133f65f2dab31ee7855009bf918f602)) 79 | 80 | ### Bug Fixes 81 | 82 | - use only SfCommand ([4beef40](https://github.com/salesforcecli/cli-taxonomy-experiment/commit/4beef400e330caa88b56cd24718cb7d56ed31cc2)) 83 | 84 | ### [1.4.2](https://github.com/salesforcecli/cli-taxonomy-experiment/compare/v1.4.1...v1.4.2) (2021-06-04) 85 | 86 | ### Bug Fixes 87 | 88 | - show error if no accounts are authorized ([4334409](https://github.com/salesforcecli/cli-taxonomy-experiment/commit/43344093a77966586bae7c50032122a916173f68)) 89 | 90 | ### [1.4.1](https://github.com/salesforcecli/cli-taxonomy-experiment/compare/v1.4.0...v1.4.1) (2021-05-24) 91 | 92 | ### Bug Fixes 93 | 94 | - update columns on env list ([9582ecb](https://github.com/salesforcecli/cli-taxonomy-experiment/commit/9582ecbe367c3b20348a93e5f5dfc348baf48d0f)) 95 | 96 | ## [1.4.0](https://github.com/salesforcecli/cli-taxonomy-experiment/compare/v1.3.1...v1.4.0) (2021-05-21) 97 | 98 | ### Features 99 | 100 | - mock functions commands ([720d452](https://github.com/salesforcecli/cli-taxonomy-experiment/commit/720d45236c1ad580d9bee6316120ef0b49ffe02c)) 101 | - update login and add project deploy org ([663b148](https://github.com/salesforcecli/cli-taxonomy-experiment/commit/663b1483f958a639150eea0c95a312de89a719d9)) 102 | - update login cmd ([f996201](https://github.com/salesforcecli/cli-taxonomy-experiment/commit/f996201b565404f6ff65eaaa7d0c5dc5b14e85f8)) 103 | - updates for demo script ([55f488f](https://github.com/salesforcecli/cli-taxonomy-experiment/commit/55f488f2531c3f59a9492446126e53e091e672db)) 104 | 105 | ### Bug Fixes 106 | 107 | - split env list table ([859d538](https://github.com/salesforcecli/cli-taxonomy-experiment/commit/859d5382a7fea9801f3e0866f738701006cadd86)) 108 | - use correct key to group environments ([7f3f3c7](https://github.com/salesforcecli/cli-taxonomy-experiment/commit/7f3f3c7449f9f590b1fade06604256440abba7ae)) 109 | 110 | ### [1.3.1](https://github.com/salesforcecli/cli-taxonomy-experiment/compare/v1.3.0...v1.3.1) (2021-05-10) 111 | 112 | ## [1.3.0](https://github.com/salesforcecli/cli-taxonomy-experiment/compare/v1.2.0...v1.3.0) (2021-04-27) 113 | 114 | ### Features 115 | 116 | - add login functions ([789121a](https://github.com/salesforcecli/cli-taxonomy-experiment/commit/789121a1dc8e90f153fd88a52a8de62f6e227e97)) 117 | 118 | ## [1.2.0](https://github.com/salesforcecli/cli-taxonomy-experiment/compare/v1.1.0...v1.2.0) (2021-04-22) 119 | 120 | ### Features 121 | 122 | - functional env create commands ([b33c79f](https://github.com/salesforcecli/cli-taxonomy-experiment/commit/b33c79fe5ec7b86d248836a9dda1bd6db2a6d809)) 123 | - **config:** add config topic and commands ([b343d0e](https://github.com/salesforcecli/cli-taxonomy-experiment/commit/b343d0eb4d88311dad7baf30bb40b301a2609caa)) 124 | - **data:** add data dummy commands ([718b7ae](https://github.com/salesforcecli/cli-taxonomy-experiment/commit/718b7ae0ba62a2631024dadc52fa6af053369b2f)) 125 | - **env:** add env open dummy command ([f73ff92](https://github.com/salesforcecli/cli-taxonomy-experiment/commit/f73ff92d03a55229cbc8c50bf43fd1dbd1bc92e8)) 126 | - **env:** add some dummy env commands and fix a bunch of other dummy commands ([b65c4e6](https://github.com/salesforcecli/cli-taxonomy-experiment/commit/b65c4e6db557f5d7f0998f3ad69ce53727ab1b50)) 127 | - **event:** add event dummy commands ([23a337c](https://github.com/salesforcecli/cli-taxonomy-experiment/commit/23a337c6fecec7fa0af12ae431ddc0c9a8d7acf1)) 128 | - **logout:** add logout command ([466c8e3](https://github.com/salesforcecli/cli-taxonomy-experiment/commit/466c8e3af4a25375612d4f6e7e390c6cb0636e60)) 129 | - **package:** add dummy package commands ([06b398c](https://github.com/salesforcecli/cli-taxonomy-experiment/commit/06b398caa3bef68551c13c91554ad13cdd326e6c)) 130 | - **usage:** add usage and env usage commands ([a609be7](https://github.com/salesforcecli/cli-taxonomy-experiment/commit/a609be75271bae356196b064c1cb236f54c1598b)) 131 | 132 | ### Bug Fixes 133 | 134 | - logout of everything by default ([9485891](https://github.com/salesforcecli/cli-taxonomy-experiment/commit/9485891b2a58769e05c625f7523b7d0187b270ee)) 135 | 136 | ## [1.1.0](https://github.com/salesforcecli/cli-taxonomy-experiment/compare/v1.0.2...v1.1.0) (2021-04-05) 137 | 138 | ### Features 139 | 140 | - add new commands and interactivity ([a205f2c](https://github.com/salesforcecli/cli-taxonomy-experiment/commit/a205f2c9cec90df8c36f9c6792c4d05835c74328)) 141 | 142 | ### 1.0.2 (2021-04-01) 143 | 144 | ### Features 145 | 146 | - add whoami and update list/login ([ad4fc6b](https://github.com/salesforcecli/cli-taxonomy-experiment/commit/ad4fc6baa86919ab009a9a71c421c73524bbe086)) 147 | - change to space seperated commands ([a01716d](https://github.com/salesforcecli/cli-taxonomy-experiment/commit/a01716d3fbfa1c3365f3b44d5dd54726ac9188e1)) 148 | - update taxonomy and deps ([b82680c](https://github.com/salesforcecli/cli-taxonomy-experiment/commit/b82680c017a376a41a5d380dc78d0dbf65500f85)) 149 | 150 | ### Bug Fixes 151 | 152 | - add bin path ([e3a7643](https://github.com/salesforcecli/cli-taxonomy-experiment/commit/e3a76438efec04cde44fb7620695f3782a5d30ca)) 153 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Salesforce Open Source Community Code of Conduct 2 | 3 | ## About the Code of Conduct 4 | 5 | Equality is a core value at Salesforce. We believe a diverse and inclusive 6 | community fosters innovation and creativity, and are committed to building a 7 | culture where everyone feels included. 8 | 9 | Salesforce open-source projects are committed to providing a friendly, safe, and 10 | welcoming environment for all, regardless of gender identity and expression, 11 | sexual orientation, disability, physical appearance, body size, ethnicity, nationality, 12 | race, age, religion, level of experience, education, socioeconomic status, or 13 | other similar personal characteristics. 14 | 15 | The goal of this code of conduct is to specify a baseline standard of behavior so 16 | that people with different social values and communication styles can work 17 | together effectively, productively, and respectfully in our open source community. 18 | It also establishes a mechanism for reporting issues and resolving conflicts. 19 | 20 | All questions and reports of abusive, harassing, or otherwise unacceptable behavior 21 | in a Salesforce open-source project may be reported by contacting the Salesforce 22 | Open Source Conduct Committee at ossconduct@salesforce.com. 23 | 24 | ## Our Pledge 25 | 26 | In the interest of fostering an open and welcoming environment, we as 27 | contributors and maintainers pledge to making participation in our project and 28 | our community a harassment-free experience for everyone, regardless of gender 29 | identity and expression, sexual orientation, disability, physical appearance, 30 | body size, ethnicity, nationality, race, age, religion, level of experience, education, 31 | socioeconomic status, or other similar personal characteristics. 32 | 33 | ## Our Standards 34 | 35 | Examples of behavior that contributes to creating a positive environment 36 | include: 37 | 38 | - Using welcoming and inclusive language 39 | - Being respectful of differing viewpoints and experiences 40 | - Gracefully accepting constructive criticism 41 | - Focusing on what is best for the community 42 | - Showing empathy toward other community members 43 | 44 | Examples of unacceptable behavior by participants include: 45 | 46 | - The use of sexualized language or imagery and unwelcome sexual attention or 47 | advances 48 | - Personal attacks, insulting/derogatory comments, or trolling 49 | - Public or private harassment 50 | - Publishing, or threatening to publish, others' private information—such as 51 | a physical or electronic address—without explicit permission 52 | - Other conduct which could reasonably be considered inappropriate in a 53 | professional setting 54 | - Advocating for or encouraging any of the above behaviors 55 | 56 | ## Our Responsibilities 57 | 58 | Project maintainers are responsible for clarifying the standards of acceptable 59 | behavior and are expected to take appropriate and fair corrective action in 60 | response to any instances of unacceptable behavior. 61 | 62 | Project maintainers have the right and responsibility to remove, edit, or 63 | reject comments, commits, code, wiki edits, issues, and other contributions 64 | that are not aligned with this Code of Conduct, or to ban temporarily or 65 | permanently any contributor for other behaviors that they deem inappropriate, 66 | threatening, offensive, or harmful. 67 | 68 | ## Scope 69 | 70 | This Code of Conduct applies both within project spaces and in public spaces 71 | when an individual is representing the project or its community. Examples of 72 | representing a project or community include using an official project email 73 | address, posting via an official social media account, or acting as an appointed 74 | representative at an online or offline event. Representation of a project may be 75 | further defined and clarified by project maintainers. 76 | 77 | ## Enforcement 78 | 79 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 80 | reported by contacting the Salesforce Open Source Conduct Committee 81 | at ossconduct@salesforce.com. All complaints will be reviewed and investigated 82 | and will result in a response that is deemed necessary and appropriate to the 83 | circumstances. The committee is obligated to maintain confidentiality with 84 | regard to the reporter of an incident. Further details of specific enforcement 85 | policies may be posted separately. 86 | 87 | Project maintainers who do not follow or enforce the Code of Conduct in good 88 | faith may face temporary or permanent repercussions as determined by other 89 | members of the project's leadership and the Salesforce Open Source Conduct 90 | Committee. 91 | 92 | ## Attribution 93 | 94 | This Code of Conduct is adapted from the [Contributor Covenant][contributor-covenant-home], 95 | version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html. 96 | It includes adaptions and additions from [Go Community Code of Conduct][golang-coc], 97 | [CNCF Code of Conduct][cncf-coc], and [Microsoft Open Source Code of Conduct][microsoft-coc]. 98 | 99 | This Code of Conduct is licensed under the [Creative Commons Attribution 3.0 License][cc-by-3-us]. 100 | 101 | [contributor-covenant-home]: https://www.contributor-covenant.org 'https://www.contributor-covenant.org/' 102 | [golang-coc]: https://golang.org/conduct 103 | [cncf-coc]: https://github.com/cncf/foundation/blob/master/code-of-conduct.md 104 | [microsoft-coc]: https://opensource.microsoft.com/codeofconduct/ 105 | [cc-by-3-us]: https://creativecommons.org/licenses/by/3.0/us/ 106 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018, Salesforce.com, Inc. 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 5 | 6 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 7 | 8 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 9 | 10 | * Neither the name of Salesforce.com nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 11 | 12 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | ## Security 2 | 3 | Please report any security issue to [security@salesforce.com](mailto:security@salesforce.com) 4 | as soon as it is discovered. This library limits its runtime dependencies in 5 | order to reduce the total cost of ownership as much as can be, but all consumers 6 | should remain vigilant and have their security stakeholders review all third-party 7 | products (3PP) like this one and their dependencies. 8 | -------------------------------------------------------------------------------- /STRATEGY.md: -------------------------------------------------------------------------------- 1 | # Strategy and Structure 2 | 3 | ## What 4 | 5 | CLI Unification is an evolution of Salesforce’s CLI strategy. We're unifying all the CLIs across Salesforce’s many brands as our first step in providing a unified cross-cloud developer experience. Our ultimate goal is to provide one set of tools for all Salesforce developers to write and deploy their Salesforce apps. 6 | 7 | We're evolving the taxonomy of our Salesforce CLI to bring together existing capabilities from Salesforce CLI and other CLIs, such as Heroku and MuleSoft, to deliver net new, cross-cloud commands under the new executable, `sf`. This new executable will be bundled with `sfdx` in the same installer and work in conjunction with `sfdx` commands, until `sf` reaches (and exceeds) full feature parity with `sfdx`. 8 | 9 | ## Structure 10 | 11 | Most CLI commands in `sf` are designed around the actions you take or the job you perform when running a command, instead of focusing on product or brand names. For this universal set of jobs to be done (JTBD), the topics are cross cloud and give you the ability to perform the same type of action for multiple Salesforce products. Those actions include the ability to _deploy_ your code/metadata, _generate_ scaffolded files for different types of resources, and connect to your _environments_. These topics are opinionated, and structured so that they are, by default, cross cloud. 12 | 13 | For example, `sf project deploy` deploys the entire project that is defined in your local directory by default. If your project includes functions and a force app then both are deployed to their respective environments with the one command. Let’s say that you later include a Heroku app, some Mulesoft APIs, and a resource from Marketing Cloud in your project. In this case, `sf project deploy` deploys all of these resources to their respective environments. What if you want a more granular way of deploying changes or use a product-specific deployment feature? In that case you’d use the product-specific project deploy commands that have flag options for granular deployment. For example, `sf project deploy org` will support all the current options for `force:source:deploy` and `force:source:push`. 14 | 15 | For actions that that only exist for a given product, the commands will be available in a plug-in that is specific to a brand (such as `sf heroku`) or product (`sf connect` or `sf package`). These commands aren't currently in the demo CLI but we include the `sf heroku` and `sf package` topics for reference. 16 | 17 | ## What is sf? 18 | 19 | Instead of starting fresh, we think it’s best to evolve the Salesforce CLI into the single CLI for all the Salesforce brands and products. To do this, we are introducing a new executable `sf` that we are bundling with `sfdx` that brings a new taxonomy and standards to the Salesforce CLI experience. 20 | 21 | Creating a new executable allows us to make some different decisions about the structure of the CLI without breaking existing scripts. We want to be more strategic about how we build the information hierarchy as we think about unifying all Salesforce brands into one CLI. But we also want to bring more consistency and stability for current users. For example, `sf` will have consistent tables, terminal output, and JSON schema, which will make scripting and developing easier. But making these types of standards changes in `sfdx` would break pre-existing scripts. 22 | 23 | ## Overall CLI Improvements 24 | 25 | When designing CLI Unification we took the opportunity to improve the overall experience of using Salesforce CLI. We focused on consistency, discoverability/navigation, and speed with the following enhancements: 26 | 27 | - Spaces instead of colons in commands for improved readability 28 | - Expanded help output, with less need to go to the online documentation 29 | - Consistent standards on: 30 | - Tables 31 | - Terminal output 32 | - JSON schema 33 | - Prompting when a required flag isn't included instead of returning an error 34 | - (Optional) Fully interactive commands that allow developers less farmiliar with the CLI to use it effectively 35 | -------------------------------------------------------------------------------- /bin/dev: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const oclif = require('@oclif/core'); 4 | 5 | process.env.NODE_ENV = 'development'; 6 | 7 | // In dev mode, always show stack traces 8 | oclif.settings.debug = true; 9 | oclif.settings.tsnodeEnabled = true; 10 | 11 | require('ts-node').register(); 12 | 13 | oclif.run().then(require('@oclif/core/flush')).catch(require('@oclif/core/handle')); 14 | -------------------------------------------------------------------------------- /bin/dev.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | node "%~dp0\dev" %* -------------------------------------------------------------------------------- /bin/run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | require('@oclif/core').run() 4 | .then(require('@oclif/core/flush')) 5 | .catch(require('@oclif/core/handle')) -------------------------------------------------------------------------------- /bin/run.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | node "%~dp0\run" %* -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { extends: ['@commitlint/config-conventional'] }; 2 | -------------------------------------------------------------------------------- /messages/config.get.md: -------------------------------------------------------------------------------- 1 | # summary 2 | 3 | Get the configuration value for a given name. 4 | 5 | # examples 6 | 7 | - Get your default username. 8 | 9 | sf config get defaultusername 10 | -------------------------------------------------------------------------------- /messages/config.list.md: -------------------------------------------------------------------------------- 1 | # summary 2 | 3 | List the configuration values that you've previously set. 4 | 5 | # description 6 | 7 | Local configuration values apply only to your current project. Global values apply in any directory. 8 | -------------------------------------------------------------------------------- /messages/config.set.md: -------------------------------------------------------------------------------- 1 | # summary 2 | 3 | Set a configuration value, such as default username. 4 | 5 | # description 6 | 7 | Local configuration values apply only to your current project. Global values apply in any directory. 8 | 9 | # examples 10 | 11 | - Set the defaultusername configuration value: 12 | 13 | sf config set defaultusername=me@my.org 14 | -------------------------------------------------------------------------------- /messages/config.unset.md: -------------------------------------------------------------------------------- 1 | # summary 2 | 3 | Unset a local or global configuration value. 4 | 5 | # description 6 | 7 | Local values apply only to your current project. Global values apply in any directory. 8 | 9 | # examples 10 | 11 | - Unset the defaulusername config value: 12 | 13 | sf config unset defaultusername 14 | -------------------------------------------------------------------------------- /messages/env.alias.set.md: -------------------------------------------------------------------------------- 1 | # summary 2 | 3 | Set an alias for an environment. 4 | 5 | # description 6 | 7 | You can associate an alias with only one environment at a time. If you’ve set an alias multiple times, the alias points to the most recent environment. 8 | 9 | # examples 10 | 11 | - Set the alias "my-org" for a scratch org with username me@example.com: 12 | 13 | sf env alias set my-org=me@example.com 14 | -------------------------------------------------------------------------------- /messages/env.alias.unset.md: -------------------------------------------------------------------------------- 1 | # summary 2 | 3 | Clears an existing alias for an environment. 4 | 5 | # examples 6 | 7 | - Unset the alias "my-org": 8 | 9 | sf env alias unset my-org 10 | -------------------------------------------------------------------------------- /messages/env.connect.md: -------------------------------------------------------------------------------- 1 | # summary 2 | 3 | Connect to an environment. 4 | 5 | # description 6 | 7 | You can connect to scratch orgs, sandboxes, compute environments, production orgs, and more. 8 | 9 | # examples 10 | 11 | - Connect to a scratch org using its alias: 12 | 13 | sf env connect --target-env my-scratch-org 14 | -------------------------------------------------------------------------------- /messages/env.create.compute.md: -------------------------------------------------------------------------------- 1 | # summary 2 | 3 | Create a compute environment where functions code can be deployed. 4 | 5 | # description 6 | 7 | When creating compute environments, the --connected-org flag is required. 8 | 9 | # examples 10 | 11 | - Create a compute environment with a sandbox as a connected org: 12 | 13 | sf env create compute --alias=billingApp-Sandbox2 --connected-org=Sandbox2 14 | -------------------------------------------------------------------------------- /messages/env.create.org.md: -------------------------------------------------------------------------------- 1 | # summary 2 | 3 | Create a scratch org or sandbox org. 4 | 5 | # description 6 | 7 | Specify a configuration file or provide key=value pairs at the command line. Values specified on the command line override values in the configuration file. 8 | 9 | # examples 10 | 11 | - Create a scratch org from a configuration file and give it an alias: 12 | 13 | sf env create org -f config/enterprise-scratch-def.json -a MyScratchOrg 14 | 15 | - Override a property in the configuration file at the command-line: 16 | 17 | sf env create org -f config/enterprise-scratch-def.json -a MyScratchOrg edition=Developer 18 | 19 | - Create a sandbox: 20 | 21 | sf env create org -t sandbox -f config/dev-sandbox-def.json -a MyDevSandbox -u prodOrg 22 | -------------------------------------------------------------------------------- /messages/env.delete.md: -------------------------------------------------------------------------------- 1 | # summary 2 | 3 | Marks an environment for deletion. 4 | 5 | # description 6 | 7 | You can mark scratch orgs, sandboxes, and compute environments for deletion. 8 | 9 | # examples 10 | 11 | - Mark a scratch org with alias "my-org" for deletion: 12 | 13 | sf env delete --target-env "my-org" 14 | -------------------------------------------------------------------------------- /messages/env.display.md: -------------------------------------------------------------------------------- 1 | # summary 2 | 3 | Display details about a specific environment. 4 | 5 | # description 6 | 7 | Specify an environment with the username you used when you logged into it with the "sf login" command or its alias. Run "sf env list" to view all your environments and their aliases. 8 | 9 | The output depends on the type of environment. For example, scratch org details include the access token, alias, username of the associated Dev Hub, the creation and expiration date, the generated scratch org username, and more. 10 | 11 | Compute environment details include the associated orgs, the list of functions, the project name, and more. 12 | 13 | # examples 14 | 15 | - Display information about a scratch org with alias "my-scratch-org": 16 | 17 | sf env display --environment=my-scratch-org 18 | 19 | - Specify a username instead of an alias: 20 | 21 | sf env display --environment=test-123456-abcdefg@example.com 22 | 23 | - Specify JSON format and redirect output into a file: 24 | 25 | sf env display --environment=my-scratch-org --json > tmp/MyOrdDesc.json 26 | 27 | # flags.environment.summary 28 | 29 | Environment alias or login user. 30 | -------------------------------------------------------------------------------- /messages/env.list.md: -------------------------------------------------------------------------------- 1 | # summary 2 | 3 | List the environments you’ve created or logged into. 4 | 5 | # description 6 | 7 | By default, the command displays only active environments. For orgs, that means unexpired scratch orgs and orgs you’re currently logged into. For compute environments, it means the environments connected to orgs you’re currently logged into. Use the --all flag to list expired scratch orgs and compute environments that aren’t connected to logged-in orgs. Warning: the latter list could be very long. 8 | 9 | The output is displayed in multiple tables, one for each environment type. For example, the Salesforce Orgs table lists the non-scratch orgs you’re logged into, such as sandboxes, Dev Hubs, production orgs, and so on. Scratch orgs and compute environments get their own tables. 10 | 11 | For non-scratch orgs, the Username column refers to the user you logged into the org with. For scratch orgs it refers to the username that was generated for you when you created the scratch org. The first column indicates the default environment for each type. 12 | 13 | Run "sf env display" to view details about a specific environment. 14 | 15 | # examples 16 | 17 | - List all environments: 18 | 19 | sf env list --all 20 | 21 | - List only connected orgs. Rows from only the Salesforce Orgs table are displayed because it’s the only table with a "Status" column. 22 | 23 | sf env list --filter="Status=Connected" 24 | 25 | - List only scratch orgs that expire after May 30, 2021: 26 | 27 | sf env list --filter="Expiration>2021-05-30" 28 | 29 | # flags.all.summary 30 | 31 | Show all environments, even inactive ones. 32 | 33 | # flags.filter.summary 34 | 35 | Filter expression used to limit the output. 36 | 37 | # flags.filter.description 38 | 39 | Use the --filter flag to limit the number of displayed table rows based on a column name. The flag takes a simple expression (" = ") and uses partial string matching. For example, use "Status=Connected" to display connected orgs or "Alias=Scratch" to display aliases that contain the string "Scratch". The column name is case insensitive. 40 | 41 | Only rows from tables that have the column listed in the filter expression are displayed. 42 | 43 | # flags.columns.summary 44 | 45 | Comma-separated list of columns to display. 46 | 47 | # flags.sort.summary 48 | 49 | Column to sort on. Default is ascending order, prepend "-" for descending. 50 | -------------------------------------------------------------------------------- /messages/env.log.get.md: -------------------------------------------------------------------------------- 1 | # summary 2 | 3 | Get the logs for a compute environment. 4 | -------------------------------------------------------------------------------- /messages/env.log.list.md: -------------------------------------------------------------------------------- 1 | # summary 2 | 3 | List the logs for a compute environment. 4 | -------------------------------------------------------------------------------- /messages/env.log.tail.md: -------------------------------------------------------------------------------- 1 | # summary 2 | 3 | Tail the logs for a compute environment. 4 | 5 | # description 6 | 7 | Command terminates after 1 hour of activity. You can't retrieve logs from before the command is run. 8 | 9 | # examples 10 | 11 | - Tail the logs of the compute environment billingApp-Scratch1: 12 | 13 | sf env log tail --environment=billingApp-Scratch1 14 | -------------------------------------------------------------------------------- /messages/env.logdrain.add.md: -------------------------------------------------------------------------------- 1 | # summary 2 | 3 | Add a log drain to a specified environment. 4 | 5 | # examples 6 | 7 | - Add a log drain to the billingApp-Sandbox environment and specify the URL that receives the logs. 8 | 9 | sf env logdrain add --environment=billingApp-Sandbox --url=syslog-a.logdna.com:11137 10 | -------------------------------------------------------------------------------- /messages/env.logdrain.list.md: -------------------------------------------------------------------------------- 1 | # summary 2 | 3 | List log drains connected to a specified environment. 4 | 5 | # examples 6 | 7 | - List the log drains associated with the billingApp-Sandbox environment: 8 | 9 | sf env logdrain list --environment=billingApp-Sandbox 10 | -------------------------------------------------------------------------------- /messages/env.logdrain.remove.md: -------------------------------------------------------------------------------- 1 | # summary 2 | 3 | Remove a log drain from a specified environment. 4 | 5 | # examples 6 | 7 | sf env logdrain remove --environment=billingApp-Sandbox --url=syslog-a.logdna.com:11137 8 | -------------------------------------------------------------------------------- /messages/env.open.md: -------------------------------------------------------------------------------- 1 | # summary 2 | 3 | Open an environment in your web browser. 4 | 5 | # description 6 | 7 | You can open the following types of environments in a web browser: scratch orgs, sandboxes, Dev Hubs, and production orgs. 8 | 9 | If you run the command without flags, it attempts to open your default environment in your default web browser. 10 | 11 | Each of your environments is associated with an instance URL, such as https://login.salesforce.com. To open a specific web page at that URL, specify the portion of the URL after "/" with the --path flag, such as /apex/YourPage to open a Visualforce page. 12 | 13 | # examples 14 | 15 | - To open your default environment, run the command without flags: 16 | 17 | sf env open 18 | 19 | - Open the Visualforce page /apex/StartHere in a scratch org with alias "test-org": 20 | 21 | sf env open --target-env test-org --path /apex/StartHere 22 | 23 | - View the URL but not launch it in a browser: 24 | 25 | sf env open --target-env test-org --path /apex/StartHere --url-only 26 | 27 | - Open the environment in the Google Chrome browser: 28 | 29 | sf env open --target-env test-org --path /apex/StartHere --browser chrome 30 | 31 | # flags.path.summary 32 | 33 | Path to append to the end of the login URL. 34 | 35 | # flags.url-only.summary 36 | 37 | Display the URL, but don’t launch it in a browser. 38 | 39 | # flags.target-env.summary 40 | 41 | Environment name or alias to open. 42 | 43 | # flags.target-env.description 44 | 45 | Specify the login user or alias that’s associated with the environment. For scratch orgs, the login user is generated by the command that created the scratch org. You can also set an alias for the scratch org when you create it. 46 | 47 | For Dev Hubs, sandboxes, and production orgs, specify the alias you set when you logged into the org with "sf login". 48 | 49 | # flags.browser.summary 50 | 51 | Browser in which to open the environment. 52 | 53 | # flags.browser.description 54 | 55 | You can specify that the environment open in one of the following browsers: Firefox, Safari, Google Chrome, or Windows Edge. If you don’t specify --browser, the environment opens in your default browser. 56 | -------------------------------------------------------------------------------- /messages/env.usage.md: -------------------------------------------------------------------------------- 1 | # summary 2 | 3 | Display usage information for an envirnoment. 4 | 5 | # description 6 | 7 | For orgs, the usage is the Apex API usage. 8 | 9 | -------------------------------------------------------------------------------- /messages/env.var.get.md: -------------------------------------------------------------------------------- 1 | # summary 2 | 3 | Get the value of one or more server-side environment variables. 4 | 5 | # examples 6 | 7 | - Get the value of the GITHUB_USERNAME environment variable set on the billingApp-Scratch1 compute environment. 8 | 9 | sf env var get GITHUB_USERNAME --environment=billingApp-Scratch1 10 | -------------------------------------------------------------------------------- /messages/env.var.list.md: -------------------------------------------------------------------------------- 1 | # summary 2 | 3 | List the server-side environment variable names for a specified compute environment. 4 | 5 | # examples 6 | 7 | - List the environment variables that have been set for the billingApp-Scratch1 compute environment: 8 | 9 | sf env var list --environment=billingApp-Scratch1 10 | -------------------------------------------------------------------------------- /messages/env.var.set.md: -------------------------------------------------------------------------------- 1 | # summary 2 | 3 | Set the value of one or more specified server-side environment variables. 4 | 5 | # examples 6 | 7 | - Set the GITHUB_USERNAME environment variable on the billingApp-Scratch1 compute environment: 8 | 9 | sf env var set GITHUB_USERNAME=stevesmith --environment=billingApp-Scratch1 10 | -------------------------------------------------------------------------------- /messages/env.var.unset.md: -------------------------------------------------------------------------------- 1 | # summary 2 | 3 | Remove the key of one or more specified server-side environment variables. 4 | 5 | # examples 6 | 7 | - Unset the GITHUB_USERNAME environment variable on the billingApp-Scratch1 compute environment: 8 | 9 | sf env var unset GITHUB_USERNAME --environment=billingApp-Scratch1 10 | -------------------------------------------------------------------------------- /messages/generate.analytics.template.md: -------------------------------------------------------------------------------- 1 | # summary 2 | 3 | Generate a simple analytics template. 4 | 5 | # description 6 | 7 | If you don’t explicitly set the API version, it defaults to the current API version. The associated metadata files are created. 8 | 9 | The outputdir can be an absolute path or relative to the current working directory. 10 | 11 | # examples 12 | 13 | - Generate an analytics template called MyTemplate: 14 | 15 | sf generate analytics template --template-name MyTemplate 16 | -------------------------------------------------------------------------------- /messages/generate.apex.class.md: -------------------------------------------------------------------------------- 1 | # summary 2 | 3 | Generate an empty Apex class. 4 | 5 | # description 6 | 7 | The command creates a .cls file and associated metadata file. 8 | 9 | You can generate the class in the current directory or specify another directory. 10 | 11 | If you don’t explicitly set the API version, it defaults to the current API version. 12 | 13 | # examples 14 | 15 | - Generate an Apex class called MyApexClass, and all its assocated files, in the current directory: 16 | 17 | sf generate apex class --class-name "MyApexClass" 18 | -------------------------------------------------------------------------------- /messages/generate.apex.test.md: -------------------------------------------------------------------------------- 1 | # summary 2 | 3 | Generate an empty Apex test for a specified Apex class. 4 | 5 | # description 6 | 7 | All associated .cls and metadata files are also created. 8 | 9 | # examples 10 | 11 | - Generate an Apex test for the Apex class MyApexClass: 12 | 13 | sf generate apex test --classname MyApexClass 14 | -------------------------------------------------------------------------------- /messages/generate.apex.trigger.md: -------------------------------------------------------------------------------- 1 | # summary 2 | 3 | Generate an empty Apex trigger. 4 | 5 | # description 6 | 7 | The command creates a .trigger file and associated metadata file. 8 | 9 | You can generate the trigger in the current directory or specify another directory. 10 | 11 | If you don’t explicitly set the API version, it defaults to the current API version. 12 | 13 | # examples 14 | 15 | - Generate an Apex trigger called MyTrigger, and all its assocated files, in the current directory: 16 | 17 | sf generate apex trigger --trigger-name "MyTrigger" 18 | -------------------------------------------------------------------------------- /messages/generate.community.md: -------------------------------------------------------------------------------- 1 | # summary 2 | 3 | Generate an Experience Cloud site using a template. 4 | 5 | # description 6 | 7 | When you execute this command, it creates the site in preview status, which means that it isn’t yet live. After you finish building your site, you can make it live. 8 | 9 | When generating a site, template-specific optional parameters can be passed in via the form of templateParams.name=value. Name and values are case-sensitive. 10 | 11 | # examples 12 | 13 | - Generate an Experience Cloud site called MyCustomerCommunity with a specified template. 14 | 15 | sf generate community --name "MyCustomerCommunity" --templatename "Customer Service" --urlpathprefix customers --description "My customer community" 16 | -------------------------------------------------------------------------------- /messages/generate.function.md: -------------------------------------------------------------------------------- 1 | # summary 2 | 3 | Add a function module to the "functions" project directory. 4 | 5 | # description 6 | 7 | Specify the function's programming language, such as Typescript or Javascript, with the --language flag. 8 | 9 | # examples 10 | 11 | - Generate a Typescript function called myFunction: 12 | 13 | sf generate function --name=myFunction --language=typescript 14 | -------------------------------------------------------------------------------- /messages/generate.lightning.component.md: -------------------------------------------------------------------------------- 1 | # summary 2 | 3 | Generate a bundle for an Aura component or a Lightning web component. 4 | 5 | # description 6 | 7 | The bundle consists of multiple files in a folder with the designated name. 8 | 9 | If not supplied, the apiversion, template, and outputdir use default values. 10 | 11 | The outputdir can be an absolute path or relative to the current working directory. 12 | 13 | If you don’t specify an outputdir, we create a subfolder in your current working directory with the name of your bundle. For example, if the current working directory is force-app and your Lightning bundle is called myBundle, we create force-app/myBundle/ to store the files in the bundle. 14 | 15 | To generate a Lightning web component, pass --type lwc to the command. If you don’t include a --type value, Salesforce CLI generates an Aura component by default. 16 | 17 | # examples 18 | 19 | - Generate a Lightning web component called MyLwcComponent: 20 | 21 | sf generate lightning component --component-name MyLwcComponent --type lwc 22 | -------------------------------------------------------------------------------- /messages/generate.lightning.event.md: -------------------------------------------------------------------------------- 1 | # summary 2 | 3 | Generate a Lightning event bundle. 4 | 5 | # description 6 | 7 | The bundle consists of multiple files in a folder with the designated name. 8 | 9 | If not supplied, the apiversion, template, and outputdir use default values. 10 | 11 | The outputdir can be an absolute path or relative to the current working directory. 12 | 13 | If you don’t specify an outputdir, we create a subfolder in your current working directory with the name of your bundle. For example, if the current working directory is force-app and your Lightning bundle is called myBundle, we create force-app/myBundle/ to store the files in the bundle. 14 | 15 | # examples 16 | 17 | - Generate a Lightening event called MyEvent: 18 | 19 | sf generate lightning event --event-name MyEvent 20 | -------------------------------------------------------------------------------- /messages/generate.lightning.interface.md: -------------------------------------------------------------------------------- 1 | # summary 2 | 3 | Generate a Lightning interface bundle. 4 | 5 | # description 6 | 7 | The bundle consists of multiple files in a folder with the designated name. 8 | 9 | If not supplied, the apiversion, template, and outputdir use default values. 10 | 11 | The outputdir can be an absolute path or relative to the current working directory. 12 | 13 | If you don’t specify an outputdir, we create a subfolder in your current working directory with the name of your bundle. For example, if the current working directory is force-app and your Lightning bundle is called myBundle, we create force-app/myBundle/ to store the files in the bundle. 14 | 15 | # examples 16 | 17 | - Generate a Lightening interface called MyInterface: 18 | 19 | sf generate lightning interface --interface-name MyInterface 20 | -------------------------------------------------------------------------------- /messages/generate.project.md: -------------------------------------------------------------------------------- 1 | # summary 2 | 3 | Generate a Salesforce DX project. 4 | 5 | # description 6 | 7 | The command creates the necessary configuration file and directories. 8 | 9 | You can generate the project in the current working directory or a specified directory. 10 | 11 | If not supplied, the apiversion, template, and outputdir use default values. 12 | 13 | The outputdir can be an absolute path or relative to the current working directory. 14 | 15 | # examples 16 | 17 | - Generate a Salesforce DX project called MyProject in the current directory: 18 | 19 | sf generate project --project-name MyProject 20 | -------------------------------------------------------------------------------- /messages/login.md: -------------------------------------------------------------------------------- 1 | # summary 2 | 3 | Log in interactively to a Salesforce org or other environment. 4 | 5 | # description 6 | 7 | The command first lists all the environments you can currently log into. After you chose one, the command provides a way for you to log into it, such as with a browser that opens https://login.salesforce.com for an org. Depending on the environment you chose, the command then prompts for other actions, such as whether to give an org an alias or set it as your default. 8 | 9 | This command is fully interactive and has no flags other than displaying the command line help. Each environment that you can log into has its own command, such as "sf login org". The environment-specific commands sometimes provide more flag options than this interactive command does. For more information about the interactive prompts from this command, see the help for the environment-specific command, such as "sf login org --help". 10 | -------------------------------------------------------------------------------- /messages/login.org.jwt.md: -------------------------------------------------------------------------------- 1 | # summary 2 | 3 | Log in to a Salesforce org using a JSON web token (JWT). 4 | 5 | # description 6 | 7 | Use this command in automated environments where you can’t interactively log in with a browser, such as in CI/CD scripts. 8 | 9 | Logging into an org authorizes the CLI to run other commands that connect to that org, such as deploying or retrieving a project. You can log into many types of orgs, such as sandboxes, Dev Hubs, Env Hubs, production orgs, and scratch orgs. 10 | 11 | Complete these steps before you run this command: 12 | 13 | 1. Create a digital certificate (also called digital signature) and the private key to sign the certificate. You can use your own key and certificate issued by a certification authority. Or use OpenSSL to create a key and a self-signed digital certificate. 14 | 2. Store the private key in a file on your computer. When you run this command, you set the --jwt-key-file flag to this file. 15 | 3. Create a custom connected app in your org using the digital certificate. Make note of the consumer key (also called cliend id) that’s generated for you. When you run this command, you set the --clientid flag to the consumer key. Be sure the username of the user logging in is approved to use the connected app. 16 | 17 | We recommend that you set an alias when you log into an org. Aliases make it easy to later reference this org when running commands that require it. If you don’t set an alias, you use the username that you specified when you logged in to the org. If you run multiple commands that reference the same org, consider setting the org as your default. 18 | 19 | # examples 20 | 21 | - This example shows a user with username jdoe@example.org logging into an org on the default instance URL (https://login.salesforce.org). The private key is stored in the file /Users/jdoe/JWT/server.key and the command uses the connected app with consumer key (client id) 04580y4051234051. 22 | 23 | sf login org jwt --username jdoe@example.org --jwt-key-file /Users/jdoe/JWT/server.key --clientid 04580y4051234051 24 | 25 | - Set the org as the default and gives it an alias: 26 | sf login org jwt --username jdoe@example.org --jwt-key-file /Users/jdoe/JWT/server.key --clientid 04580y4051234051 --alias ci-org --set-default 27 | 28 | - Use the --instance-url flag log in to a sandbox: 29 | 30 | sf login org jwt --username jdoe@example.org --jwt-key-file /Users/jdoe/JWT/server.key --clientid 04580y4051234051 --alias ci-org --set-default --instance-url https://test.salesforce.com 31 | 32 | # flags.alias.summary 33 | 34 | Alias for the org. 35 | 36 | # flags.instance-url.summary 37 | 38 | URL of the instance that the org lives on. (defaults to https://login.salesforce.com) 39 | 40 | # flags.instance-url.description 41 | 42 | If you specify an --instance-url value, this value overrides the sfdcLoginUrl value in your sfdx-project.json file. 43 | 44 | To specify a My Domain URL, use the format https://yourcompanyname.my.salesforce.com. 45 | 46 | To specify a sandbox, set --instance-url to https://test.salesforce.com. 47 | 48 | # flags.set-default.summary 49 | 50 | Set the org as your default org. 51 | 52 | # flags.client-id.summary 53 | 54 | OAuth client id (also called consumer key) of your custom connected app. 55 | 56 | # flags.jwt-key-file.summary 57 | 58 | Path to a file containing the private key. 59 | 60 | # flags.username.summary 61 | 62 | Username of the user logging in. 63 | 64 | # flags.audience-url.summary 65 | 66 | Audience URL for the given instance URL. 67 | 68 | # flags.audience-url.description 69 | 70 | Overrides the aud (audience) field used for JWT authentication so that it matches the expected value of the authorization server URL for the org you’re logging into. For example, "http://login.salesforce.com" for a production org or "https://test.salesforce.com" for a sandbox. 71 | -------------------------------------------------------------------------------- /messages/login.org.md: -------------------------------------------------------------------------------- 1 | # summary 2 | 3 | Log in to a Salesforce org using the web server flow. 4 | 5 | # description 6 | 7 | This command opens a Salesforce instance URL in a web browser for you to then enter your credentials and log in to your org. After you log in, you can close the browser window. 8 | 9 | Logging into an org authorizes the CLI to run other commands that connect to that org, such as deploying or retrieving a project. You can log into many types of orgs, such as sandboxes, Dev Hubs, Env Hubs, production orgs, and scratch orgs. 10 | 11 | We recommend that you set an alias when you log into an org. Aliases make it easy to later reference this org when running commands that require it. If you don’t set an alias, you use the username that you specified when you logged in to the org. If you run multiple commands that reference the same org, consider setting the org as your default. 12 | 13 | By default, this command uses the global out-of-the-box connected app in your org. If you need more security or control, such as setting the refresh token timeout or specifying IP ranges, create your own connected app. Then specify its consumer key with the --clientid flag. 14 | 15 | # examples 16 | 17 | - If your org lives on the standard Salesforce login page (https://login.salesforce.com), run the command with no flags to log in: 18 | 19 | sf login org 20 | 21 | - If you log in to your Dev Hub, set an alias so you can reference it later when you create a scratch org: 22 | 23 | sf login org --alias dev-hub 24 | 25 | - Log in to a sandbox and set it as your default org: 26 | 27 | sf login org --instance-url https://test.salesforce.com --set-default 28 | 29 | - Use --browser to specify a specific browser, such as Google Chrome: 30 | 31 | sf login org --instance-url https://test.salesforce.com --set-default --browser chrome 32 | 33 | - Use your own connected app by specifying its consumer key: 34 | 35 | sf login org --instance-url https://test.salesforce.com --set-default --browser chrome --clientid 04580y4051234051 36 | 37 | # flags.alias.summary 38 | 39 | Alias for the org. 40 | 41 | # flags.instance-url.summary 42 | 43 | URL of the instance that the org lives on. (defaults to https://login.salesforce.com) 44 | 45 | # flags.instance-url.description 46 | 47 | If you specify --instance-url, the value overrides the sfdcLoginUrl value in your sfdx-project.json file. 48 | 49 | To specify a My Domain URL, use the format https://yourcompanyname.my.salesforce.com. 50 | 51 | To specify a sandbox, set --instance-url to https://test.salesforce.com. 52 | 53 | # flags.client-id.summary 54 | 55 | OAuth client id (also called consumer key) of your custom connected app. 56 | 57 | # flags.browser.summary 58 | 59 | Browser in which to open the org. 60 | 61 | # flags.browser.description 62 | 63 | You can specify that you want to log in to an org with one of the following browsers: Firefox, Safari, Google Chrome, or Windows Edge. If you don’t specify --browser, you log in using your default browser. 64 | 65 | # flags.set-default.summary 66 | 67 | Set the org as your default org. 68 | -------------------------------------------------------------------------------- /messages/logout.md: -------------------------------------------------------------------------------- 1 | # summary 2 | 3 | Log out of all Salesforce orgs and environments. 4 | -------------------------------------------------------------------------------- /messages/logout.org.md: -------------------------------------------------------------------------------- 1 | # summary 2 | 3 | Log out of a specified Salesforce org. 4 | 5 | # examples 6 | 7 | - Log out of an org with alias "ci-org": 8 | 9 | sf logout org --target-org ci-org 10 | 11 | - If your org doesn’t have an alias, specify the username that you used when you logged into it: 12 | 13 | sf logout org --target-org jdoe@example.org 14 | 15 | # flags.target-org.summary 16 | 17 | Org alias or username to log out of. 18 | 19 | -------------------------------------------------------------------------------- /messages/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "HelpDefaults": "If not supplied, the apiversion, template, and outputdir use default values.\n", 3 | "HelpOutputDirRelative": "The outputdir can be an absolute path or relative to the current working directory.\n", 4 | "HelpOutputDirRelativeLightning": "If you don’t specify an outputdir, we create a subfolder in your current working directory with the name of your bundle. For example, if the current working directory is force-app and your Lightning bundle is called myBundle, we create force-app/myBundle/ to store the files in the bundle.\n", 5 | "HelpExamplesTitle": "\nExamples:\n", 6 | "OutputDirFlagDescription": "folder for saving the created files", 7 | "OutputDirFlagLongDescription": "The directory to store the newly created files. The location can be an absolute path or relative to the current working directory. The default is the current directory.", 8 | "TemplateFlagDescription": "template to use for file creation", 9 | "TemplateFlagLongDescription": "The template to use to create the file. Supplied parameter values or default values are filled into a copy of the template.", 10 | "TargetDirOutput": "target dir = %s", 11 | "App": "app", 12 | "Event": "event", 13 | "Interface": "interface", 14 | "Test": "test", 15 | "Component": "component", 16 | "Page": "page", 17 | 18 | "AlphaNumericNameError": "Name must contain only alphanumeric characters.", 19 | "NameMustStartWithLetterError": "Name must start with a letter.", 20 | "EndWithUnderscoreError": "Name can't end with an underscore.", 21 | "DoubleUnderscoreError": "Name can't contain 2 consecutive underscores." 22 | } 23 | -------------------------------------------------------------------------------- /messages/org.json: -------------------------------------------------------------------------------- 1 | { 2 | "commandDescription": "print a greeting and your org IDs", 3 | "nameFlagDescription": "name to print", 4 | "forceFlagDescription": "example boolean flag", 5 | "errorNoOrgResults": "No results found for the org '%s'." 6 | } 7 | -------------------------------------------------------------------------------- /messages/project.deploy.functions.md: -------------------------------------------------------------------------------- 1 | # summary 2 | 3 | Deploy all functions in this project to a specified compute environment. 4 | 5 | # examples 6 | 7 | - Deploy all functions to the connected org with alias "Scratch1": 8 | 9 | sf project deploy functions --connected-org=Scratch1 10 | -------------------------------------------------------------------------------- /messages/project.deploy.md: -------------------------------------------------------------------------------- 1 | # summary 2 | 3 | Deploy a project interactively to any Salesforce environment. 4 | 5 | # description 6 | 7 | The command first analyzes your project, active or logged-into environments, and local defaults to determine what to deploy and where. The command then prompts you for information about this particular deployment and provides intelligent choices based on its analysis. 8 | 9 | For example, if your local project contains a package directory with metadata source files, the command asks if you want to deploy that Salesforce app to an org. The command lists your connected orgs and asks which one you want to deploy to. If the command finds Apex tests, it asks if you want to run them and at which level. 10 | 11 | Similarly, if the command finds a local functions directory, the command prompts if you want to deploy it and to which compute environment. The command prompts and connects you to a compute environment of your choice if you’re not currently connected to any. 12 | 13 | This command must be run from within a project. 14 | 15 | The command stores your responses in a local file and uses them as defaults when you rerun the command. Specify --interactive to force the command to reprompt. 16 | 17 | Use this command for quick and simple deploys. For more complicated deployments, use the environment-specific commands, such as "sf project deploy org", that provide additional flags. 18 | 19 | # flags.interactive.summary 20 | 21 | Force the CLI to prompt for all deployment inputs. 22 | -------------------------------------------------------------------------------- /messages/project.deploy.org.md: -------------------------------------------------------------------------------- 1 | # summary 2 | 3 | Deploy source and metadata to an org. 4 | 5 | # description 6 | 7 | The source you deploy overwrites the corresponding metadata in your org. This command doesn’t attempt to merge your source with the versions in your org. If the command detects a conflict, it displays the conflicts but doesn’t complete the process. After reviewing the conflict, rerun the command with the --force-overwrite flag to overwrite the org. 8 | 9 | To run the command asynchronously, set --wait to 0, which immediately returns the job ID. This way, you can continue to use the CLI. By default the command waits to finish no matter how long the deployment takes. 10 | 11 | To run a quick deploy of a recently validated package, use --validated-deploy-request-id with the validated ID. 12 | 13 | You must run this command from wihin a project. 14 | 15 | If the comma-separated list you’re supplying contains spaces, enclose the entire comma-separated list in one set of double quotes. On Windows, if the list contains commas, also enclose the entire list in one set of double quotes. 16 | 17 | # examples 18 | 19 | - Deploy the source files in a directory: 20 | 21 | sf project deploy org --deploy-dir path/to/source 22 | 23 | - Deploy a specific Apex class and the objects whose source is in a directory: 24 | 25 | sf project deploy org --deploy-dir "path/to/apex/classes/MyClass.cls,path/to/source/objects" 26 | 27 | - Deploy source files in a comma-separated list that contains spaces: 28 | 29 | sf project deploy org --deploy-dir "path/to/objects/MyCustomObject/fields/MyField.field-meta.xml, path/to/apex/classes" 30 | 31 | - Deploy all Apex classes: 32 | 33 | sf project deploy org --metadata ApexClass 34 | 35 | - Deploy a specific Apex class: 36 | 37 | sf project deploy org --metadata ApexClass:MyApexClass 38 | 39 | - Deploy all custom objects and Apex classes: 40 | 41 | sf project deploy org --metadata "CustomObject,ApexClass" 42 | 43 | - Deploy all Apex classes and two specific profiles (one of which has a space in its name): 44 | 45 | sf project deploy org --metadata "ApexClass, Profile:My Profile, Profile: AnotherProfile" 46 | 47 | - Deploy all components listed in a manifest: 48 | 49 | sf project deploy org --manifest path/to/package.xml 50 | 51 | - Run the tests that aren’t in any managed packages as part of a deployment: 52 | 53 | sf project deploy org --metadata ApexClass --test-level RunLocalTests 54 | 55 | - Check whether a deployment would succeed (to prepare for Quick Deploy): 56 | 57 | sf project deploy org --metadata ApexClass --test-level RunAllTestsInOrg --check-only 58 | 59 | - Deploy an already validated deployment (Quick Deploy): 60 | 61 | sf project deploy org --validated-deploy-request-id 0Af9A00000FTM6pSAH 62 | 63 | - Deploy a .zip file: 64 | 65 | sf project deploy org --zip-file path/to/zip/mypackage.zip 66 | 67 | - Deploy a .zip file that points to a single package: 68 | 69 | sf project deploy org --zip-file path/to/zip/mypackage.zip --single-package 70 | 71 | # flags.check-only.summary 72 | 73 | Validate deploy and run Apex tests but don’t save to the org. 74 | 75 | # flags.check-only.description 76 | 77 | If you change a field type from Master-Detail to Lookup or vice versa, that change isn’t supported when using the --check-only parameter to test a deployment (validation). This kind of change isn’t supported for test deployments to avoid the risk of data loss or corruption. If a change that isn’t supported for test deployments is included in a deployment package, the test deployment fails and issues an error. 78 | 79 | If your deployment package changes a field type from Master-Detail to Lookup or vice versa, you can still validate the changes prior to deploying to Production by performing a full deployment to another test Sandbox. A full deployment includes a validation of the changes as part of the deployment process. 80 | 81 | Note: A Metadata API deployment that includes Master-Detail relationships deletes all detail records in the Recycle Bin in the following cases. 82 | 83 | 1. For a deployment with a new Master-Detail field, soft delete (send to the Recycle Bin) all detail records before proceeding to deploy the Master-Detail field, or the deployment fails. During the deployment, detail records are permanently deleted from the Recycle Bin and cannot be recovered. 84 | 85 | 2. For a deployment that converts a Lookup field relationship to a Master-Detail relationship, detail records must reference a master record or be soft-deleted (sent to the Recycle Bin) for the deployment to succeed. However, a successful deployment permanently deletes any detail records in the Recycle Bin. 86 | 87 | # flags.deploy-dir.summary 88 | 89 | Root of local directory tree of files to deploy. 90 | 91 | # flags.deploy-dir.description 92 | 93 | The root must contain a valid package.xml file describing the entities in the directory structure. This flag is requiredto initiate a deployment if you don’t use --zip-file. If you specify both --zip-file and --deploy-dir, a zip file of the contents of the --deploy-dir directory is written to the location specified by --zip-file. 94 | 95 | If you specify this flag, don’t specify --metadata or --manifest. 96 | 97 | # flags.zip-file.summary 98 | 99 | Path to .zip file of metadata to deploy. 100 | 101 | # flags.zip-file.description 102 | 103 | You must indicate this flag or --deploy-dir. If you specify both --zip-file and --deploy-dir, a .zip file of the contents of the deploy directory is created at the path specified for the .zip file. 104 | 105 | # flags.ignore-warnings.summary 106 | 107 | Ignore warnings and allow a deployment to complete successfully. 108 | 109 | # flags.ignore-warnings.description 110 | 111 | The default is to not ignore warnings. If a warning occurs and you specified this flag, the success field in DeployMessage is set to true. If you didn’t specify this flag, success is set to false, and the warning is treated like an error. 112 | 113 | # flags.test-level.summary 114 | 115 | Deployment Apex testing level. 116 | 117 | # flags.test-level.description 118 | 119 | Valid values are: 120 | 121 | - NoTestRun — No tests are run. This test level applies only to deployments to development environments, such as sandbox, Developer Edition, or trial orgs. This test level is the default for development environments. 122 | 123 | - RunSpecifiedTests — Runs only the tests that you specify with the --run-tests flag. Code coverage requirements differ from the default coverage requirements when using this test level. Executed tests must comprise a minimum of 75% code coverage for each class and trigger in the deployment package. This coverage is computed for each class and trigger individually and is different than the overall coverage percentage. 124 | 125 | - RunLocalTests — All tests in your org are run, except the ones that originate from installed managed packages. This test level is the default for production deployments that include Apex classes or triggers. 126 | 127 | - RunAllTestsInOrg — All tests in your org are run, including tests of managed packages. 128 | 129 | If you don’t specify a test level, the default behavior depends on the contents of your deployment package. For more information, see “Running Tests in a Deployment” in the Metadata API Developer Guide. 130 | 131 | # flags.ignore-errors.summary 132 | 133 | Ignore any errors and don’t roll back deployment. 134 | 135 | # flags.ignore-errors.description 136 | 137 | The default is to not ignore errors. Don’t specify this flag when deploying to a production org. If you specify the flag, components without errors are deployed, and components with errors are skipped. 138 | 139 | # flags.validated-deploy-request-id.summary 140 | 141 | Request ID of the validated deployment to run a Quick Deploy. 142 | 143 | # flags.validated-deploy-request-id.description 144 | 145 | Specifies the ID of a package with recently validated components to run a Quick Deploy. Deploying a validation helps you shorten your deployment time because tests aren’t rerun. If you have a recent successful validation, you can deploy the validated components without running tests. A validation doesn’t save any components in the org. 146 | 147 | You use a validation only to check the success or failure messages that you would receive with an actual deployment. It doesn’t validate your components. This flag sets the checkOnly="true" parameter for your deployment. Before deploying a recent validation, ensure that the following requirements are met: 148 | 149 | 1. The components have been validated successfully for the target environment within the last 10 days. 150 | 2. As part of the validation, Apex tests in the target org have passed. 151 | 3. Code coverage requirements are met: 152 | 153 | - If all tests in the org or all local tests are run, overall code coverage is at least 75%, and Apex triggers have some coverage. 154 | - If specific tests are run with the RunSpecifiedTests test level, each class and trigger that was deployed is covered by at least 75% individually. 155 | 156 | # flags.run-tests.summary 157 | 158 | Apex tests to run when --test-level is RunSpecifiedTests. 159 | 160 | # flags.single-package.summary 161 | 162 | Indicates that the zip file points to a directory structure for a single package. 163 | 164 | # flags.single-package.description 165 | 166 | Use this flag with the --zip-file flag. By default, the CLI assumes the directory is structured for a set of packages. 167 | 168 | # flags.wait.summary 169 | 170 | Number of minutes to wait for command to complete. 171 | 172 | # flags.wait.description 173 | 174 | Default is -1 (no limit). 175 | 176 | # flags.soapdeploy.summary 177 | 178 | Deploy metadata with SOAP API instead of the default REST API. 179 | 180 | # flags.soapdeploy.description 181 | 182 | Because SOAP API has a lower .ZIP file size limit (400 MB uncompressed, 39 MB compressed), Salesforce recommends REST API deployment. This flag provides backwards compatibility with API version 50.0 and earlier when deploy used SOAP API by default. 183 | 184 | # flags.metadata.summary 185 | 186 | Comma-separated list of metadata component names to deploy. 187 | 188 | # flags.manifest.summary 189 | 190 | Full file path for manifest (package.xml) of components to deploy. 191 | 192 | # flags.manifest.description 193 | 194 | If you specify this flag, don’t specify --metadata or --deploy-dir. 195 | 196 | # flags.force-overwrite.summary 197 | 198 | Ignore source conflict warnings and overwrite changes to the org. 199 | -------------------------------------------------------------------------------- /messages/project.retrieve.md: -------------------------------------------------------------------------------- 1 | # summary 2 | 3 | Retrieve source interactively from a Salesforce org. 4 | 5 | # description 6 | 7 | The command first analyzes your project, active or logged-into orgs, and local defaults to determine what to retrieve. The command then prompts you for information about this particular retrieve and provides intelligent choices based on its analysis. 8 | 9 | This command must be run from within a project. 10 | 11 | The command stores your responses in a local file and uses them as defaults when you rerun the command. Specify --interactive to force the command to reprompt. 12 | 13 | Use this command for quick and simple retrieves. For more complicated scenarios, use "sf project retrieve org" which provides additional flags. 14 | 15 | # flags.interactive.summary 16 | 17 | Force the CLI to prompt for all inputs. 18 | -------------------------------------------------------------------------------- /messages/project.retrieve.org.md: -------------------------------------------------------------------------------- 1 | # summary 2 | 3 | Retrieve source from an org. 4 | 5 | # description 6 | 7 | The source you retrieve overwrites the corresponding source files in your local project . This command doesn’t attempt to merge the source from your org with your local source files. If the command detects a conflict, it displays the conflicts but doesn’t complete the process. After reviewing the conflict, rerun the command with the --force-overwrite flag to overwrite your local files. 8 | 9 | If the comma-separated list you’re supplying contains spaces, enclose the entire comma-separated list in one set of double quotes. On Windows, if the list contains commas, also enclose the entire list in one set of double quotes. 10 | 11 | You must run this command from wihin a project. 12 | 13 | # examples 14 | 15 | - Retrieve the source files in a directory: 16 | 17 | sf project retrieve org --source-path path/to/source 18 | 19 | - Retrieve a specific Apex class and the objects whose source is in a directory: 20 | 21 | sf project retrieve org --source-path "path/to/apex/classes/MyClass.cls,path/to/source/objects" 22 | 23 | - Retrieve source files in a comma-separated list that contains spaces: 24 | 25 | sf project retrieve org --source-path "path/to/objects/MyCustomObject/fields/MyField.field-meta.xml, path/to/apex/classes" 26 | 27 | - Retrieve all Apex classes: 28 | 29 | sf project retrieve org --metadata ApexClass 30 | 31 | - Retrieve a specific Apex class: 32 | 33 | sf project retrieve org --metadata ApexClass:MyApexClass 34 | 35 | - Retrieve all custom objects and Apex classes: 36 | 37 | sf project retrieve org --metadata "CustomObject,ApexClass" 38 | 39 | - Retrieve all metadata components listed in a manifest: 40 | 41 | sf project retrieve org --manifest path/to/package.xml 42 | 43 | - Retrieve metadata from a package: 44 | 45 | sf project retrieve org --package-names MyPackageName 46 | 47 | - Retrieve metadata from multiple packages: 48 | 49 | sf project retrieve org --package-names "Package1, PackageName With Spaces, Package3" 50 | -------------------------------------------------------------------------------- /messages/run.apex.md: -------------------------------------------------------------------------------- 1 | # summary 2 | 3 | Execute anonymous Apex code. 4 | 5 | # description 6 | 7 | The command executes one or more lines of code entered on the command line, or executes the code in a local file. 8 | 9 | To execute your code interactively, run this command with no parameters. At the prompt, enter all your Apex code; press CTRL-D when you're finished. Your code is then executed in a single execute anonymous request. 10 | 11 | For more information, see "Anonymous Blocks" in the Apex Developer Guide. 12 | 13 | # examples 14 | 15 | - Execute the anonymous Apex code in the test.apex file in your home directory on org with alias "my-org" 16 | 17 | sf run apex --target-env my-org --apex-code-file ~/test.apex 18 | -------------------------------------------------------------------------------- /messages/run.function.md: -------------------------------------------------------------------------------- 1 | # summary 2 | 3 | Invoke a locally running function. 4 | 5 | -------------------------------------------------------------------------------- /messages/run.function.start.md: -------------------------------------------------------------------------------- 1 | # summary 2 | 3 | Start a locally running function. 4 | 5 | -------------------------------------------------------------------------------- /messages/test.apex.md: -------------------------------------------------------------------------------- 1 | # summary 2 | 3 | Invoke Apex tests. 4 | 5 | # description 6 | 7 | Specify which tests to run by using the --class-names, --suites, or --tests parameters. Alternatively, use the --test-level parameter to run all the tests in your org, local tests, or specified tests. 8 | 9 | To see code coverage results, use the --code-cmverage parameter with --result-format. The output displays a high-level summary of the test run and the code coverage values for classes in your org. If you specify human-readable result format, use the --detailed-coverage parameter to see detailed coverage results for each test method run. 10 | 11 | NOTE: The testRunCoverage value (JSON and JUnit result formats) is a percentage of the covered lines and total lines from all the Apex classes evaluated by the tests in this run. 12 | 13 | # examples 14 | 15 | - Invoke specific Apex tests and display the output in human-readable format: 16 | 17 | sf test apex --class-names "MyClassTest,MyOtherClassTest" --result-format human 18 | -------------------------------------------------------------------------------- /messages/test.function.md: -------------------------------------------------------------------------------- 1 | # summary 2 | 3 | Test a locally running function. 4 | 5 | -------------------------------------------------------------------------------- /messages/usage.md: -------------------------------------------------------------------------------- 1 | # summary 2 | 3 | Display overall usage of your compute spend. 4 | -------------------------------------------------------------------------------- /messages/whoami.md: -------------------------------------------------------------------------------- 1 | # summary 2 | 3 | Display details of the current logged-in account and user. 4 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@salesforce/sf-demo", 3 | "description": "An experiment to explore a new taxonomy for all Salesforce clouds.", 4 | "version": "1.6.7", 5 | "author": "Salesforce", 6 | "keywords": [], 7 | "license": "BSD-3-Clause", 8 | "repository": "salesforcecli/cli-taxonomy-experiment", 9 | "homepage": "https://github.com/salesforcecli/cli-taxonomy-experiment", 10 | "bugs": "https://github.com/salesforcecli/cli-taxonomy-experiment/issues", 11 | "bin": { 12 | "sf": "bin/run" 13 | }, 14 | "engines": { 15 | "node": ">=12.0.0" 16 | }, 17 | "files": [ 18 | "/lib", 19 | "/messages", 20 | "/bin" 21 | ], 22 | "oclif": { 23 | "bin": "sf", 24 | "commands": "./lib/commands", 25 | "hooks": { 26 | "init": "./lib/hooks/readme.js" 27 | }, 28 | "plugins": [ 29 | "@oclif/plugin-plugins" 30 | ], 31 | "devPlugins": [ 32 | "oclif" 33 | ], 34 | "topicSeparator": " ", 35 | "topics": { 36 | "env": { 37 | "description": "Manage orgs and compute environments.", 38 | "subtopics": { 39 | "create": { 40 | "description": "Create environments." 41 | }, 42 | "alias": { 43 | "description": "Manage environment aliases." 44 | }, 45 | "log": { 46 | "description": "View logs." 47 | }, 48 | "logdrain": { 49 | "description": "Manage log drains." 50 | }, 51 | "var": { 52 | "description": "Manage environment variables." 53 | } 54 | } 55 | }, 56 | "login": { 57 | "description": "Log into environments.", 58 | "subtopics": { 59 | "org": { 60 | "description": "Log into an org." 61 | } 62 | } 63 | }, 64 | "logout": { 65 | "description": "Log out of environments." 66 | }, 67 | "config": { 68 | "description": "Configure Salesforce CLI." 69 | }, 70 | "data": { 71 | "description": "Manipulate records in your org." 72 | }, 73 | "event": { 74 | "description": "Manage events." 75 | }, 76 | "generate": { 77 | "description": "Generate local code, such as a project or Apex class.", 78 | "subtopics": { 79 | "analytics": { 80 | "description": "Create analytics templates." 81 | }, 82 | "apex": { 83 | "description": "Create Apex classes and triggers." 84 | }, 85 | "lightning": { 86 | "description": "Create Aura and Lightning Web components ." 87 | } 88 | } 89 | }, 90 | "project": { 91 | "description": "Deploy and retrieve artifacts between your project and an environment.", 92 | "subtopics": { 93 | "deploy": { 94 | "description": "Deploy artifacts." 95 | }, 96 | "retrieve": { 97 | "description": "Retrieve artifacts." 98 | } 99 | } 100 | }, 101 | "run": { 102 | "description": "Run code, such as anonymous Apex.", 103 | "subtopics": { 104 | "function": { 105 | "description": "Run functions." 106 | } 107 | } 108 | }, 109 | "test": { 110 | "description": "Invoke tests in an environment." 111 | }, 112 | "heroku": { 113 | "description": "Invoke Heroku commands." 114 | }, 115 | "plugins": { 116 | "description": "Manage CLI plug-ins." 117 | }, 118 | "package": { 119 | "description": "Develop and install packages." 120 | } 121 | } 122 | }, 123 | "dependencies": { 124 | "@oclif/core": "^0.5.14", 125 | "@oclif/plugin-plugins": "^1.10.0", 126 | "@salesforce/core": "3.1.1-v3.1", 127 | "@salesforce/kit": "^1.5.14", 128 | "chalk": "^4.1.0", 129 | "cli-ux": "^5.6.2", 130 | "inquirer": "^8.1.1", 131 | "tslib": "^2.3.0" 132 | }, 133 | "devDependencies": { 134 | "@salesforce/dev-config": "^2.1.2", 135 | "@salesforce/dev-scripts": "0.9.15", 136 | "@salesforce/prettier-config": "^0.0.2", 137 | "@salesforce/ts-sinon": "1.3.18", 138 | "@types/inquirer": "^7.3.2", 139 | "@typescript-eslint/eslint-plugin": "^4.28.0", 140 | "@typescript-eslint/parser": "^4.28.0", 141 | "chai": "^4.2.0", 142 | "cz-conventional-changelog": "^3.2.0", 143 | "eslint": "^7.29.0", 144 | "eslint-config-prettier": "^8.3.0", 145 | "eslint-config-salesforce": "^0.1.6", 146 | "eslint-config-salesforce-license": "^0.1.6", 147 | "eslint-config-salesforce-typescript": "^0.2.7", 148 | "eslint-plugin-header": "^3.0.0", 149 | "eslint-plugin-import": "^2.23.4", 150 | "eslint-plugin-jsdoc": "^35.4.0", 151 | "eslint-plugin-prettier": "^3.1.3", 152 | "husky": "^4.3.8", 153 | "lint-staged": "^11.0.0", 154 | "mocha": "^9.0.1", 155 | "nyc": "^15.1.0", 156 | "oclif": "^1.18.0", 157 | "prettier": "^2.3.1", 158 | "pretty-quick": "^3.1.1", 159 | "shx": "0.3.3", 160 | "sinon": "^11.1.1", 161 | "ts-node": "^10.0.0", 162 | "typescript": "^4.3.4" 163 | }, 164 | "config": { 165 | "commitizen": { 166 | "path": "cz-conventional-changelog" 167 | } 168 | }, 169 | "scripts": { 170 | "build": "sf-build", 171 | "clean": "sf-clean", 172 | "clean-all": "sf-clean all", 173 | "clean:lib": "shx rm -rf lib && shx rm -rf coverage && shx rm -rf .nyc_output && shx rm -f oclif.manifest.json", 174 | "compile": "sf-compile", 175 | "docs": "sf-docs", 176 | "format": "sf-format", 177 | "lint": "sf-lint", 178 | "postpack": "shx rm -f oclif.manifest.json", 179 | "posttest": "yarn lint", 180 | "prepack": "sf-prepack", 181 | "prepare": "sf-install", 182 | "pretest": "sf-compile-test", 183 | "test": "sf-test", 184 | "version": "./bin/dev readme && git add README.md" 185 | }, 186 | "husky": { 187 | "hooks": { 188 | "pre-commit": "sf-husky-pre-commit", 189 | "commit-msg": "sf-husky-commit-msg", 190 | "pre-push": "sf-husky-pre-push" 191 | } 192 | }, 193 | "publishConfig": { 194 | "access": "public" 195 | } 196 | } 197 | -------------------------------------------------------------------------------- /src/commands/config/get.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { Messages } from '@salesforce/core'; 9 | import SfCommand from '../../sf-command'; 10 | 11 | Messages.importMessagesDirectory(__dirname); 12 | const messages = Messages.loadMessages('@salesforce/sf-demo', 'config.get'); 13 | 14 | export default class ConfigGet extends SfCommand { 15 | public static summary = messages.getMessage('summary'); 16 | 17 | public static examples = messages.getMessages('examples'); 18 | 19 | public async run(): Promise { 20 | this.log('Get Configs...'); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/commands/config/list.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { Messages } from '@salesforce/core'; 9 | import SfCommand from '../../sf-command'; 10 | 11 | Messages.importMessagesDirectory(__dirname); 12 | const messages = Messages.loadMessages('@salesforce/sf-demo', 'config.list'); 13 | 14 | export default class ConfigList extends SfCommand { 15 | public static summary = messages.getMessage('summary'); 16 | public static description = messages.getMessage('description'); 17 | 18 | public async run(): Promise { 19 | this.log('List Configs...'); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/commands/config/set.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { Messages } from '@salesforce/core'; 9 | import SfCommand from '../../sf-command'; 10 | 11 | Messages.importMessagesDirectory(__dirname); 12 | const messages = Messages.loadMessages('@salesforce/sf-demo', 'config.set'); 13 | 14 | export default class ConfigSet extends SfCommand { 15 | public static summary = messages.getMessage('summary'); 16 | public static description = messages.getMessage('description'); 17 | 18 | public static examples = messages.getMessages('examples'); 19 | 20 | public async run(): Promise { 21 | this.log('Setting Config...'); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/commands/config/unset.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { Messages } from '@salesforce/core'; 9 | import SfCommand from '../../sf-command'; 10 | 11 | Messages.importMessagesDirectory(__dirname); 12 | const messages = Messages.loadMessages('@salesforce/sf-demo', 'config.unset'); 13 | 14 | export default class ConfigUnset extends SfCommand { 15 | public static summary = messages.getMessage('summary'); 16 | public static description = messages.getMessage('description'); 17 | 18 | public static examples = messages.getMessages('examples'); 19 | 20 | public async run(): Promise { 21 | this.log('Unsetting Config...'); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/commands/data/data.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import SfCommand from '../../sf-command'; 9 | 10 | export default class Data extends SfCommand { 11 | public static description = 'Placeholder topic'; 12 | 13 | public static examples = ['sf data ...']; 14 | 15 | public async run(): Promise { 16 | this.log('This is a placeholder topic for data commands...'); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/commands/env/alias/set.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { AnyJson } from '@salesforce/ts-types'; 9 | import { Flags } from '@oclif/core'; 10 | 11 | import { Messages } from '@salesforce/core'; 12 | import SfCommand from '../../../sf-command'; 13 | 14 | Messages.importMessagesDirectory(__dirname); 15 | const messages = Messages.loadMessages('@salesforce/sf-demo', 'env.alias.set'); 16 | 17 | export default class EnvAliasSet extends SfCommand { 18 | public static summary = messages.getMessage('summary'); 19 | public static description = messages.getMessage('description'); 20 | 21 | public static examples = messages.getMessages('examples'); 22 | 23 | public static args = [{ name: 'alias' }]; 24 | 25 | public static flags = { 26 | targetEnv: Flags.string({ 27 | char: 't', 28 | description: 'The environment to set an alias for', 29 | }), 30 | }; 31 | 32 | public async run(): Promise { 33 | const { flags, args } = await this.parse(EnvAliasSet); 34 | 35 | this.log(`Setting ${args.alias as string} as ${flags.targetEnv}...\n`); 36 | 37 | return { flags, args }; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/commands/env/alias/unset.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { AnyJson } from '@salesforce/ts-types'; 9 | import { Flags } from '@oclif/core'; 10 | 11 | import { Messages } from '@salesforce/core'; 12 | import SfCommand from '../../../sf-command'; 13 | 14 | Messages.importMessagesDirectory(__dirname); 15 | const messages = Messages.loadMessages('@salesforce/sf-demo', 'env.alias.unset'); 16 | 17 | export default class EnvAliasUnset extends SfCommand { 18 | public static summary = messages.getMessage('summary'); 19 | 20 | public static examples = messages.getMessages('examples'); 21 | 22 | public static args = [{ name: 'alias' }]; 23 | 24 | public static flags = { 25 | targetEnv: Flags.string({ 26 | char: 't', 27 | description: 'The environment to unset an alias for', 28 | }), 29 | }; 30 | 31 | public async run(): Promise { 32 | const { flags, args } = await this.parse(EnvAliasUnset); 33 | 34 | this.log(`Unsetting ${args.alias as string} as ${flags.targetEnv}...\n`); 35 | 36 | return { flags, args }; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/commands/env/connect.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { Flags, Errors } from '@oclif/core'; 9 | import { AnyJson } from '@salesforce/ts-types'; 10 | import { blue, cyan } from 'chalk'; 11 | import { Messages } from '@salesforce/core'; 12 | import SfCommand from '../../sf-command'; 13 | import Environments from '../../configs/environments'; 14 | import Aliases from '../../configs/aliases'; 15 | 16 | Messages.importMessagesDirectory(__dirname); 17 | const messages = Messages.loadMessages('@salesforce/sf-demo', 'env.connect'); 18 | 19 | export default class EnvConnect extends SfCommand { 20 | public static summary = messages.getMessage('summary'); 21 | public static description = messages.getMessage('description'); 22 | 23 | public static examples = messages.getMessages('examples'); 24 | 25 | public static hidden = true; 26 | public static flags = { 27 | name: Flags.string({ 28 | description: 'name of the remote environment to connect to', 29 | required: true, 30 | }), 31 | alias: Flags.string({ 32 | description: 'alias to give to the environment', 33 | }), 34 | }; 35 | 36 | public async run(): Promise { 37 | const { flags, args } = await this.parse(EnvConnect); 38 | 39 | const remotes = await Environments.retrieveRemote(); 40 | 41 | const environment = remotes.find((remote) => remote.name === flags.name); 42 | 43 | if (!environment) { 44 | throw new Errors.CLIError( 45 | `No remote environment ${flags.name} found.\n\n - Try ${blue( 46 | 'sf env list --remotes' 47 | )} to see environments to connect to.`, 48 | { 49 | // This doesn't work... TODO figure out why 50 | suggestions: [`Try ${blue('sf env list --remotes')} to see environments to connect to.`], 51 | } 52 | ); 53 | } 54 | await Environments.connect(environment); 55 | 56 | if (flags.alias) { 57 | Aliases.set(flags.alias, flags.name); 58 | } 59 | 60 | this.log(`Connected to ${cyan(flags.name)}`); 61 | return { flags, args }; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/commands/env/create/compute.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { Messages } from '@salesforce/core'; 9 | import Environments from '../../../configs/environments'; 10 | import { Environment, ComputeEnvironment } from '../../../configs/environments'; 11 | import SfCommand from '../../../sf-command'; 12 | 13 | Messages.importMessagesDirectory(__dirname); 14 | const messages = Messages.loadMessages('@salesforce/sf-demo', 'env.create.compute'); 15 | export default class EnvCreateCompute extends SfCommand { 16 | public static summary = messages.getMessage('summary'); 17 | public static description = messages.getMessage('description'); 18 | 19 | public static examples = messages.getMessages('examples'); 20 | 21 | public static args = [{ name: 'envName' }]; 22 | 23 | public async run(): Promise { 24 | const { args } = await this.parse(EnvCreateCompute); 25 | const environments = Environments.getInstance(); 26 | 27 | const env: Environment = { 28 | name: args.envName as string, 29 | aliases: [], 30 | connected: false, 31 | status: 'not connected', 32 | type: 'compute', 33 | context: '', 34 | token: '', 35 | }; 36 | 37 | try { 38 | environments.set(args.envName, env); 39 | await environments.write(); 40 | this.log(`Created ${args.envName as string}\n`); 41 | } catch (e) { 42 | this.log(`Failed to create ${args.envName as string}\n`); 43 | this.error(e, { exit: 1 }); 44 | } 45 | 46 | return env as ComputeEnvironment; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/commands/env/create/org.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { Messages } from '@salesforce/core'; 9 | import Environments from '../../../configs/environments'; 10 | import { Environment, OrgEnvironment } from '../../../configs/environments'; 11 | import SfCommand from '../../../sf-command'; 12 | 13 | Messages.importMessagesDirectory(__dirname); 14 | const messages = Messages.loadMessages('@salesforce/sf-demo', 'env.create.org'); 15 | export default class EnvCreateOrg extends SfCommand { 16 | public static summary = messages.getMessage('summary'); 17 | public static description = messages.getMessage('description'); 18 | 19 | public static examples = messages.getMessages('examples'); 20 | 21 | public static args = [{ name: 'envName' }]; 22 | 23 | public async run(): Promise { 24 | const { args } = await this.parse(EnvCreateOrg); 25 | const environments = Environments.getInstance(); 26 | 27 | const env: Environment = { 28 | name: args.envName as string, 29 | aliases: [], 30 | connected: false, 31 | status: 'not connected', 32 | type: 'org', 33 | context: '', 34 | token: '', 35 | }; 36 | 37 | try { 38 | environments.set(args.envName, env); 39 | await environments.write(); 40 | this.log(`Created ${args.envName as string}\n`); 41 | } catch (e) { 42 | this.log(`Failed to create ${args.envName as string}\n`); 43 | this.error(e, { exit: 1 }); 44 | } 45 | 46 | return env as OrgEnvironment; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/commands/env/delete.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { Flags, Errors } from '@oclif/core'; 9 | import { AnyJson } from '@salesforce/ts-types'; 10 | import { blue, cyan } from 'chalk'; 11 | import { Messages } from '@salesforce/core'; 12 | import SfCommand from '../../sf-command'; 13 | import Environments from '../../configs/environments'; 14 | import Aliases from '../../configs/aliases'; 15 | 16 | Messages.importMessagesDirectory(__dirname); 17 | const messages = Messages.loadMessages('@salesforce/sf-demo', 'env.delete'); 18 | 19 | export default class EnvConnect extends SfCommand { 20 | public static summary = messages.getMessage('summary'); 21 | public static description = messages.getMessage('description'); 22 | 23 | public static examples = messages.getMessages('examples'); 24 | 25 | public static hidden = true; 26 | public static flags = { 27 | name: Flags.string({ 28 | description: 'name of the environment to delete', 29 | required: true, 30 | }), 31 | alias: Flags.string({ 32 | char: 'a', 33 | description: 'alias of the environment to delete', 34 | }), 35 | }; 36 | 37 | public async run(): Promise { 38 | const { flags, args } = await this.parse(EnvConnect); 39 | 40 | const remotes = await Environments.retrieveRemote(); 41 | 42 | const environment = remotes.find((remote) => remote.name === flags.name); 43 | 44 | if (!environment) { 45 | throw new Errors.CLIError( 46 | `No remote environment ${flags.name} found.\n\n - Try ${blue( 47 | 'sf env list --remotes' 48 | )} to see environments to connect to.`, 49 | { 50 | // This doesn't work... TODO figure out why 51 | suggestions: [`Try ${blue('sf env list --remotes')} to see environments to connect to.`], 52 | } 53 | ); 54 | } 55 | await Environments.connect(environment); 56 | 57 | if (flags.alias) { 58 | Aliases.set(flags.alias, flags.name); 59 | } 60 | 61 | this.log(`Connected to ${cyan(flags.name)}`); 62 | return { flags, args }; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/commands/env/display.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { Flags } from '@oclif/core'; 9 | import { Messages } from '@salesforce/core'; 10 | import SfCommand from '../../sf-command'; 11 | 12 | Messages.importMessagesDirectory(__dirname); 13 | const messages = Messages.loadMessages('@salesforce/sf-demo', 'env.display'); 14 | 15 | export default class EnvDisplay extends SfCommand { 16 | public static summary = messages.getMessage('summary'); 17 | public static description = messages.getMessage('description'); 18 | 19 | public static examples = messages.getMessages('examples'); 20 | 21 | public static flags = { 22 | environment: Flags.string({ 23 | summary: messages.getMessage('flags.environment.summary'), 24 | required: true, 25 | char: 'e', 26 | }), 27 | }; 28 | 29 | public async run(): Promise { 30 | this.log('Diplaying env...'); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/commands/env/list.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { EOL } from 'os'; 9 | import { Flags, Interfaces } from '@oclif/core'; 10 | import { AnyJson } from '@salesforce/ts-types'; 11 | import { cli } from 'cli-ux'; 12 | import { bold, green, red } from 'chalk'; 13 | import { Messages } from '@salesforce/core'; 14 | import SfCommand from '../../sf-command'; 15 | import { Environment } from '../../configs/environments'; 16 | 17 | Messages.importMessagesDirectory(__dirname); 18 | const messages = Messages.loadMessages('@salesforce/sf-demo', 'env.list'); 19 | 20 | type DisplayEnvironment = Environment & { alias: string }; 21 | export default class EnvList extends SfCommand { 22 | public static summary = messages.getMessage('summary'); 23 | public static description = messages.getMessage('description'); 24 | 25 | public static examples = messages.getMessages('examples'); 26 | 27 | public static flags = { 28 | all: Flags.boolean({ 29 | description: 'include enviornments not yet connected', 30 | }), 31 | // Hack beause typings has changed in oclif/core. cli-ux needs to be updated, maybe even include cli-ux in core if small enough 32 | ...(cli.table.flags() as unknown as Interfaces.FlagInput), 33 | }; 34 | 35 | public convertEnvironmentEntry(entry: [string, Environment]): DisplayEnvironment { 36 | return this.convertEnvironment(entry[0], entry[1]); 37 | } 38 | 39 | public convertEnvironment( 40 | name: string, 41 | environment: Environment, 42 | defaults: Partial = { 43 | connected: false, 44 | status: 'Not Connected', 45 | } 46 | ): DisplayEnvironment { 47 | // First merge defaults and the environment in a copy. 48 | const copy = Object.assign({}, defaults, environment); 49 | if (copy.type === 'org') { 50 | // Override values on the copy to look nicer in the CLI table. 51 | return Object.assign(copy, { 52 | name, 53 | username: bold(name), 54 | alias: this.aliases.getKeysByValue(name)[0] || '', 55 | status: copy.connected ? green(copy.status) : red(copy.status), 56 | orgId: copy.orgId || 'Unknown', 57 | }); 58 | } else if (copy.type === 'compute') { 59 | // Override values on the copy to look nicer in the CLI table. 60 | const orgId = (this.environments.getContents()[copy.connectedOrg] as Environment).orgId; 61 | const orgAlias = this.aliases.getKeysByValue(copy.connectedOrg)[0]; 62 | return Object.assign(copy, { 63 | name, 64 | alias: this.aliases.getKeysByValue(name)[0] || '', 65 | projectName: bold(name), 66 | orgAlias, 67 | orgId, 68 | status: copy.connected ? green(copy.status) : red(copy.status), 69 | }); 70 | } 71 | } 72 | 73 | public retrieveRemoteEnvironments(): DisplayEnvironment[] { 74 | // No server interactions in this experiement, so use a fake remote env list stored locally in the auth file. 75 | return this.accounts.entries().reduce((list, [name, account]) => { 76 | const type = name === 'heroku' || name === 'functions' ? 'compute' : 'org'; 77 | const accountEnvironments = account.environments.map((environmentsName) => { 78 | let context: string; 79 | 80 | if (name === 'heroku') { 81 | context = 'heroku app'; 82 | } else if (name === 'functions') { 83 | context = 'functions'; 84 | } else if (name === 'org') { 85 | if (environmentsName.includes('scratch')) { 86 | context = 'scratch'; 87 | } else { 88 | context = 'sandbox'; 89 | } 90 | } else { 91 | context = 'unknown'; 92 | } 93 | 94 | return this.convertEnvironment(environmentsName, { 95 | name: environmentsName, 96 | connectedOrg: account.user, 97 | type, 98 | context, 99 | }); 100 | }); 101 | 102 | return [...list, ...accountEnvironments]; 103 | }, [] as DisplayEnvironment[]); 104 | } 105 | 106 | public async run(): Promise { 107 | const { flags, args } = await this.parse(EnvList); 108 | 109 | const heroku = this.accounts.get('heroku'); 110 | const connectedEnvironments = this.environments.entries().map((entry) => this.convertEnvironmentEntry(entry)); 111 | 112 | let allEnvironments = connectedEnvironments; 113 | 114 | if (flags.all) { 115 | // Remove dups 116 | const remoteEnvironments = this.retrieveRemoteEnvironments().filter( 117 | (remoteEnv) => !connectedEnvironments.find((env) => env.name === remoteEnv.name) 118 | ); 119 | allEnvironments = [...allEnvironments, ...remoteEnvironments]; 120 | } 121 | 122 | if (allEnvironments.length === 0) { 123 | this.log('No environements connected. Use "sf login" or "sf env connect" to connected enviornments.'); 124 | 125 | if (heroku) { 126 | this.log('Use "--all" to see available envionments.'); 127 | } 128 | return; 129 | } 130 | 131 | const groupedByType = allEnvironments.reduce((x, y) => { 132 | const type = y.type || 'unknown'; 133 | if (x[type]) { 134 | x[type] = [...x[type], y]; 135 | } else { 136 | x[y.type] = [y]; 137 | } 138 | return x; 139 | }, {} as Record); 140 | 141 | const typeToHeader = { 142 | org: 'Salesforce Orgs', 143 | compute: 'Compute Environments', 144 | unknown: 'Unknown', 145 | }; 146 | 147 | // Salesforce Orgs 148 | cli.table( 149 | groupedByType.org, 150 | { 151 | alias: {}, 152 | username: {}, 153 | orgId: { header: 'Org ID' }, 154 | status: {}, 155 | }, 156 | { 157 | ...flags, 158 | title: typeToHeader.org, 159 | } 160 | ); 161 | 162 | console.log(EOL); 163 | 164 | // Compute Environments 165 | cli.table( 166 | groupedByType.compute, 167 | { 168 | alias: {}, 169 | projectName: { header: 'Project Name' }, 170 | orgAlias: { header: 'Connected Org Alias' }, 171 | orgId: { header: 'Connected Org ID' }, 172 | status: {}, 173 | }, 174 | { 175 | ...flags, 176 | title: typeToHeader.compute, 177 | } 178 | ); 179 | this.log(); 180 | return { flags, args }; 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /src/commands/env/log/get.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { Messages } from '@salesforce/core'; 9 | import SfCommand from '../../../sf-command'; 10 | 11 | Messages.importMessagesDirectory(__dirname); 12 | const messages = Messages.loadMessages('@salesforce/sf-demo', 'env.log.get'); 13 | 14 | export default class EnvLogGet extends SfCommand { 15 | public static summary = messages.getMessage('summary'); 16 | 17 | public async run(): Promise { 18 | this.log('Getting env logs...'); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/commands/env/log/list.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { Messages } from '@salesforce/core'; 9 | import SfCommand from '../../../sf-command'; 10 | 11 | Messages.importMessagesDirectory(__dirname); 12 | const messages = Messages.loadMessages('@salesforce/sf-demo', 'env.log.list'); 13 | 14 | export default class EnvLogList extends SfCommand { 15 | public static summary = messages.getMessage('summary'); 16 | 17 | public async run(): Promise { 18 | this.log('Listing env logs...'); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/commands/env/log/tail.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { Messages } from '@salesforce/core'; 9 | import SfCommand from '../../../sf-command'; 10 | 11 | Messages.importMessagesDirectory(__dirname); 12 | const messages = Messages.loadMessages('@salesforce/sf-demo', 'env.log.tail'); 13 | 14 | export default class EnvLogGet extends SfCommand { 15 | public static summary = messages.getMessage('summary'); 16 | public static description = messages.getMessage('description'); 17 | 18 | public static examples = messages.getMessages('examples'); 19 | 20 | public async run(): Promise { 21 | this.log('Streaming env logs...'); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/commands/env/logdrain/add.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { Messages } from '@salesforce/core'; 9 | import SfCommand from '../../../sf-command'; 10 | 11 | Messages.importMessagesDirectory(__dirname); 12 | const messages = Messages.loadMessages('@salesforce/sf-demo', 'env.logdrain.add'); 13 | 14 | export default class EnvLogdrainAdd extends SfCommand { 15 | public static summary = messages.getMessage('summary'); 16 | 17 | public static examples = messages.getMessages('examples'); 18 | 19 | public async run(): Promise { 20 | this.log('Adding log drain...'); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/commands/env/logdrain/list.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { Messages } from '@salesforce/core'; 9 | import SfCommand from '../../../sf-command'; 10 | 11 | Messages.importMessagesDirectory(__dirname); 12 | const messages = Messages.loadMessages('@salesforce/sf-demo', 'env.logdrain.list'); 13 | 14 | export default class EnvLogdrainList extends SfCommand { 15 | public static summary = messages.getMessage('summary'); 16 | 17 | public static examples = messages.getMessages('examples'); 18 | 19 | public async run(): Promise { 20 | this.log('Listing log drains...'); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/commands/env/logdrain/remove.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { Messages } from '@salesforce/core'; 9 | import SfCommand from '../../../sf-command'; 10 | 11 | Messages.importMessagesDirectory(__dirname); 12 | const messages = Messages.loadMessages('@salesforce/sf-demo', 'env.logdrain.remove'); 13 | 14 | export default class EnvLogdrainRemove extends SfCommand { 15 | public static summary = messages.getMessage('summary'); 16 | 17 | public static examples = messages.getMessages('examples'); 18 | 19 | public async run(): Promise { 20 | this.log('Removing log drain...'); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/commands/env/open.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { Flags } from '@oclif/core'; 9 | import { Messages } from '@salesforce/core'; 10 | 11 | import SfCommand from '../../sf-command'; 12 | 13 | Messages.importMessagesDirectory(__dirname); 14 | const messages = Messages.loadMessages('@salesforce/sf-demo', 'env.open'); 15 | 16 | export default class EnvOpen extends SfCommand { 17 | public static summary = messages.getMessage('summary'); 18 | public static description = messages.getMessage('description'); 19 | 20 | public static examples = messages.getMessages('examples'); 21 | 22 | public static flags = { 23 | path: Flags.string({ 24 | char: 'p', 25 | summary: messages.getMessage('flags.path.summary'), 26 | }), 27 | 'url-only': Flags.boolean({ 28 | char: 'r', 29 | summary: messages.getMessage('flags.url-only.summary'), 30 | }), 31 | 'target-env': Flags.string({ 32 | char: 'e', 33 | summary: messages.getMessage('flags.target-env.summary'), 34 | description: messages.getMessage('flags.target-env.description'), 35 | }), 36 | browser: Flags.string({ 37 | summary: messages.getMessage('flags.browser.summary'), 38 | description: messages.getMessage('flags.browser.description'), 39 | }), 40 | }; 41 | 42 | public async run(): Promise { 43 | const { flags /* , args */ } = await this.parse(EnvOpen); 44 | 45 | const browser = flags.browser || 'browser'; 46 | 47 | this.log(`Opening env in ${browser}...\n`); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/commands/env/usage.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { cli } from 'cli-ux'; 9 | import { Flags } from '@oclif/core'; 10 | 11 | import { Messages } from '@salesforce/core'; 12 | import SfCommand from '../../sf-command'; 13 | 14 | Messages.importMessagesDirectory(__dirname); 15 | const messages = Messages.loadMessages('@salesforce/sf-demo', 'env.usage'); 16 | 17 | export default class Usage extends SfCommand { 18 | public static summary = messages.getMessage('summary'); 19 | public static description = messages.getMessage('description'); 20 | 21 | public static flags = { 22 | // TODO: Add cli.table.flags - https://github.com/oclif/cli-ux#clitable 23 | json: Flags.string({ 24 | description: 'format output as json', 25 | }), 26 | targetEnv: Flags.string({ 27 | char: 't', 28 | description: 'target environment', 29 | }), 30 | }; 31 | 32 | public async run(): Promise { 33 | cli.table( 34 | [ 35 | { Name: 'AnalyticsExternalDataSizeMB', Remaining: '40960', Max: '40960' }, 36 | { Name: 'BOZosCalloutHourlyLimit', Remaining: '20000', Max: '20000' }, 37 | { Name: 'ConcurrentAsyncGetReportInstances', Remaining: '200', Max: '200' }, 38 | { Name: 'ConcurrentEinsteinDataInsightsStoryCreation', Remaining: '5', Max: '5' }, 39 | { Name: 'ConcurrentEinsteinDiscoveryStoryCreation', Remaining: '2', Max: '2' }, 40 | { Name: 'ConcurrentSyncReportRuns', Remaining: '20', Max: '20' }, 41 | { Name: 'DailyAnalyticsDataflowJobExecutions', Remaining: '60', Max: '60' }, 42 | { Name: 'DailyAnalyticsUploadedFilesSizeMB', Remaining: '51200', Max: '51200' }, 43 | { Name: 'DailyApiRequests', Remaining: '99999', Max: '100000' }, 44 | { Name: 'DailyAsyncApexExecutions', Remaining: '250000', Max: '250000' }, 45 | { Name: 'DailyBulkApiBatches', Remaining: '15000', Max: '15000' }, 46 | ], 47 | { 48 | Name: {}, 49 | Remaining: {}, 50 | Max: {}, 51 | }, 52 | { 53 | /* TODO add cli.table.flags */ 54 | } 55 | ); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/commands/env/var/get.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { Messages } from '@salesforce/core'; 9 | import SfCommand from '../../../sf-command'; 10 | 11 | Messages.importMessagesDirectory(__dirname); 12 | const messages = Messages.loadMessages('@salesforce/sf-demo', 'env.var.get'); 13 | 14 | export default class EnvVarGet extends SfCommand { 15 | public static summary = messages.getMessage('summary'); 16 | 17 | public static examples = messages.getMessages('examples'); 18 | 19 | public async run(): Promise { 20 | this.log('Getting env var...'); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/commands/env/var/list.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { Messages } from '@salesforce/core'; 9 | import SfCommand from '../../../sf-command'; 10 | 11 | Messages.importMessagesDirectory(__dirname); 12 | const messages = Messages.loadMessages('@salesforce/sf-demo', 'env.var.list'); 13 | 14 | export default class EnvVarList extends SfCommand { 15 | public static summary = messages.getMessage('summary'); 16 | 17 | public static examples = messages.getMessages('examples'); 18 | 19 | public async run(): Promise { 20 | this.log('Listing env vars...'); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/commands/env/var/set.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { Messages } from '@salesforce/core'; 9 | import SfCommand from '../../../sf-command'; 10 | 11 | Messages.importMessagesDirectory(__dirname); 12 | const messages = Messages.loadMessages('@salesforce/sf-demo', 'env.var.set'); 13 | 14 | export default class EnvVarSet extends SfCommand { 15 | public static summary = messages.getMessage('summary'); 16 | 17 | public static examples = messages.getMessages('examples'); 18 | 19 | public async run(): Promise { 20 | this.log('Setting env var...'); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/commands/env/var/unset.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { Messages } from '@salesforce/core'; 9 | import SfCommand from '../../../sf-command'; 10 | 11 | Messages.importMessagesDirectory(__dirname); 12 | const messages = Messages.loadMessages('@salesforce/sf-demo', 'env.var.unset'); 13 | 14 | export default class EnvVarUnset extends SfCommand { 15 | public static summary = messages.getMessage('summary'); 16 | 17 | public static examples = messages.getMessages('examples'); 18 | 19 | public async run(): Promise { 20 | this.log('Unsetting env var...'); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/commands/event/event.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import SfCommand from '../../sf-command'; 9 | 10 | export default class Event extends SfCommand { 11 | public static description = 'Placeholder topic'; 12 | 13 | public static examples = ['sf event ...']; 14 | 15 | public async run(): Promise { 16 | this.log('This is a placeholder topic for event commands...'); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/commands/generate/analytics/template.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { Messages } from '@salesforce/core'; 9 | import SfCommand from '../../../sf-command'; 10 | 11 | Messages.importMessagesDirectory(__dirname); 12 | const messages = Messages.loadMessages('@salesforce/sf-demo', 'generate.analytics.template'); 13 | 14 | export default class GenerateAnalyticsTemplate extends SfCommand { 15 | public static summary = messages.getMessage('summary'); 16 | public static description = messages.getMessage('description'); 17 | 18 | public static examples = messages.getMessages('examples'); 19 | 20 | public async run(): Promise { 21 | this.log('Created analytics template.'); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/commands/generate/apex/class.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { Flags } from '@oclif/core'; 9 | import { Messages } from '@salesforce/core'; 10 | 11 | import SfCommand from '../../../sf-command'; 12 | 13 | Messages.importMessagesDirectory(__dirname); 14 | const messages = Messages.loadMessages('@salesforce/sf-demo', 'generate.apex.class'); 15 | 16 | export default class GenerateApexClass extends SfCommand { 17 | public static summary = messages.getMessage('summary'); 18 | public static description = messages.getMessage('description'); 19 | public static examples = messages.getMessages('examples'); 20 | 21 | public static flags = { 22 | 'class-name': Flags.string({ 23 | description: 'class name', 24 | char: 'n', 25 | }), 26 | }; 27 | 28 | public async run(): Promise { 29 | const { flags } = await this.parse(GenerateApexClass); 30 | this.log(`Created class ${flags['class-name']}.`); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/commands/generate/apex/test.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { Messages } from '@salesforce/core'; 9 | import SfCommand from '../../../sf-command'; 10 | 11 | Messages.importMessagesDirectory(__dirname); 12 | const messages = Messages.loadMessages('@salesforce/sf-demo', 'generate.apex.test'); 13 | 14 | export default class GenerateApexTest extends SfCommand { 15 | public static summary = messages.getMessage('summary'); 16 | public static description = messages.getMessage('description'); 17 | 18 | public static examples = messages.getMessages('examples'); 19 | 20 | public async run(): Promise { 21 | this.log('Created apex test.'); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/commands/generate/apex/trigger.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { Messages } from '@salesforce/core'; 9 | import SfCommand from '../../../sf-command'; 10 | 11 | Messages.importMessagesDirectory(__dirname); 12 | const messages = Messages.loadMessages('@salesforce/sf-demo', 'generate.apex.trigger'); 13 | 14 | export default class GenerateApexTrigger extends SfCommand { 15 | public static summary = messages.getMessage('summary'); 16 | public static description = messages.getMessage('description'); 17 | 18 | public static examples = messages.getMessages('examples'); 19 | 20 | public async run(): Promise { 21 | this.log('Created apex trigger.'); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/commands/generate/community.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { Flags } from '@oclif/core'; 9 | import { Messages } from '@salesforce/core'; 10 | 11 | import SfCommand from '../../sf-command'; 12 | 13 | Messages.importMessagesDirectory(__dirname); 14 | const messages = Messages.loadMessages('@salesforce/sf-demo', 'generate.community'); 15 | 16 | export default class GenerateCommunity extends SfCommand { 17 | public static summary = messages.getMessage('summary'); 18 | public static description = messages.getMessage('description'); 19 | 20 | public static examples = messages.getMessages('examples'); 21 | 22 | public static flags = { 23 | name: Flags.string({ 24 | description: 'community name', 25 | char: 'n', 26 | }), 27 | }; 28 | 29 | public async run(): Promise { 30 | const { flags } = await this.parse(GenerateCommunity); 31 | this.log(`Created community ${flags.name}.`); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/commands/generate/function.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { Flags } from '@oclif/core'; 9 | import { Messages } from '@salesforce/core'; 10 | import { AnyJson } from '@salesforce/ts-types'; 11 | import { green } from 'chalk'; 12 | 13 | import SfCommand from '../../sf-command'; 14 | 15 | Messages.importMessagesDirectory(__dirname); 16 | const messages = Messages.loadMessages('@salesforce/sf-demo', 'generate.function'); 17 | 18 | export default class GenerateFunction extends SfCommand { 19 | public static summary = messages.getMessage('summary'); 20 | public static description = messages.getMessage('description'); 21 | 22 | public static examples = messages.getMessages('examples'); 23 | 24 | public static flags = { 25 | language: Flags.string({ 26 | description: 'function language', 27 | char: 'l', 28 | options: ['node', 'java'], 29 | }), 30 | name: Flags.string({ 31 | description: 'function module name', 32 | char: 'n', 33 | }), 34 | }; 35 | 36 | public async run(): Promise { 37 | const { flags } = await this.parse(GenerateFunction); 38 | this.log(`Created ${flags.language} function ${green(flags.name)} in functions/${green(flags.name)}.`); 39 | return {}; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/commands/generate/lightning/component.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { Messages } from '@salesforce/core'; 9 | import SfCommand from '../../../sf-command'; 10 | 11 | Messages.importMessagesDirectory(__dirname); 12 | const messages = Messages.loadMessages('@salesforce/sf-demo', 'generate.lightning.component'); 13 | 14 | export default class GenerateLightningComponent extends SfCommand { 15 | public static summary = messages.getMessage('summary'); 16 | public static description = messages.getMessage('description'); 17 | 18 | public static examples = messages.getMessages('examples'); 19 | 20 | public async run(): Promise { 21 | this.log('Created lightning component.'); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/commands/generate/lightning/event.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { Messages } from '@salesforce/core'; 9 | import SfCommand from '../../../sf-command'; 10 | 11 | Messages.importMessagesDirectory(__dirname); 12 | const messages = Messages.loadMessages('@salesforce/sf-demo', 'generate.lightning.event'); 13 | export default class GenerateLightningEvent extends SfCommand { 14 | public static summary = messages.getMessage('summary'); 15 | public static description = messages.getMessage('description'); 16 | 17 | public static examples = messages.getMessages('examples'); 18 | 19 | public async run(): Promise { 20 | this.log('Created lightning event.'); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/commands/generate/lightning/interface.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { Messages } from '@salesforce/core'; 9 | import SfCommand from '../../../sf-command'; 10 | 11 | Messages.importMessagesDirectory(__dirname); 12 | const messages = Messages.loadMessages('@salesforce/sf-demo', 'generate.lightning.interface'); 13 | 14 | export default class GenerateLightningInterface extends SfCommand { 15 | public static summary = messages.getMessage('summary'); 16 | public static description = messages.getMessage('description'); 17 | 18 | public static examples = messages.getMessages('examples'); 19 | 20 | public async run(): Promise { 21 | this.log('Created lightning interface.'); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/commands/generate/project.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { Flags } from '@oclif/core'; 9 | import { Messages } from '@salesforce/core'; 10 | 11 | import SfCommand from '../../sf-command'; 12 | 13 | Messages.importMessagesDirectory(__dirname); 14 | const messages = Messages.loadMessages('@salesforce/sf-demo', 'generate.function'); 15 | 16 | export default class GenerateProject extends SfCommand { 17 | public static summary = messages.getMessage('summary'); 18 | public static description = messages.getMessage('description'); 19 | 20 | public static examples = messages.getMessages('examples'); 21 | 22 | public static flags = { 23 | 'project-name': Flags.string({ 24 | description: 'project name', 25 | char: 'n', 26 | }), 27 | }; 28 | 29 | public async run(): Promise { 30 | const { flags } = await this.parse(GenerateProject); 31 | this.log(`Created project ${flags['project-name']}.`); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/commands/heroku/heroku.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import SfCommand from '../../sf-command'; 9 | 10 | export default class Heroku extends SfCommand { 11 | public static description = 'Placeholder topic'; 12 | 13 | public static examples = ['sf heroku ...']; 14 | 15 | public async run(): Promise { 16 | this.log('This is a placeholder topic for the heroku plugin...'); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/commands/login.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { Messages } from '@salesforce/core'; 9 | import { AnyJson } from '@salesforce/ts-types'; 10 | import { prompt, Answers } from 'inquirer'; 11 | 12 | import SfCommand from '../sf-command'; 13 | import { loginFunctions, loginHeroku, loginOrg, LoginArgs } from '../utils'; 14 | 15 | Messages.importMessagesDirectory(__dirname); 16 | const messages = Messages.loadMessages('@salesforce/sf-demo', 'login'); 17 | 18 | // eslint-disable-next-line no-shadow 19 | export enum LoginTarget { 20 | ORG = 'Salesforce Org', 21 | FUNCTIONS = 'Salesforce Functions', 22 | HEROKU = 'Heroku', 23 | } 24 | 25 | export default class Login extends SfCommand { 26 | public static summary = messages.getMessage('summary'); 27 | public static description = messages.getMessage('description'); 28 | 29 | public static flags = {}; 30 | 31 | public async run(): Promise { 32 | const target = await this.promptUserToChooseLoginTarget(); 33 | switch (target) { 34 | case LoginTarget.ORG: 35 | return this.executeOrgLogin(); 36 | case LoginTarget.FUNCTIONS: 37 | return this.executeFunctionsLogin(); 38 | case LoginTarget.HEROKU: 39 | return this.executeHerokuLogin(); 40 | default: 41 | break; 42 | } 43 | 44 | return {}; 45 | } 46 | 47 | public async executeOrgLogin(): Promise { 48 | const args = (await this.promptUserForOrgArgs()) as LoginArgs; 49 | return loginOrg(args); 50 | } 51 | 52 | private async executeFunctionsLogin(): Promise { 53 | const args = (await this.promptUserForFunctionsArgs()) as LoginArgs; 54 | return loginFunctions(args); 55 | } 56 | 57 | private async executeHerokuLogin(): Promise { 58 | const args = (await this.promptUserForHerokuArgs()) as LoginArgs; 59 | return loginHeroku(args); 60 | } 61 | 62 | private async promptUserToChooseLoginTarget(): Promise { 63 | const responses = await prompt([ 64 | { 65 | name: 'target', 66 | message: 'What would you like to log into?', 67 | type: 'list', 68 | choices: [LoginTarget.ORG, LoginTarget.FUNCTIONS, LoginTarget.HEROKU], 69 | }, 70 | ]); 71 | 72 | return responses.target as LoginTarget; 73 | } 74 | 75 | private async promptUserForOrgArgs(): Promise { 76 | const responses = await prompt([ 77 | { 78 | name: 'alias', 79 | message: 'Set an alias for the org (leave blank for no alias)', 80 | type: 'input', 81 | }, 82 | { 83 | name: 'setDefault', 84 | message: 'Set the org as your default org?', 85 | type: 'confirm', 86 | }, 87 | ]); 88 | return responses; 89 | } 90 | 91 | private async promptUserForFunctionsArgs(): Promise { 92 | const responses = await prompt([ 93 | { 94 | name: 'jwtFile', 95 | message: 'file containing the JWT private key:', 96 | type: 'string', 97 | }, 98 | { 99 | name: 'clientId', 100 | message: 'OAuth client ID (sometimes called the consumer key):', 101 | type: 'string', 102 | }, 103 | ]); 104 | return responses; 105 | } 106 | 107 | private async promptUserForHerokuArgs(): Promise { 108 | const responses = await prompt([ 109 | { 110 | name: 'alias', 111 | message: 'Alias:', 112 | type: 'input', 113 | }, 114 | ]); 115 | return Object.assign(responses, { loginUrl: 'https://heroku.com' }); 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/commands/login/functions.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { Flags } from '@oclif/core'; 9 | import { AnyJson } from '@salesforce/ts-types'; 10 | 11 | import SfCommand from '../../sf-command'; 12 | import { Browser, loginFunctions } from '../../utils'; 13 | 14 | export default class FunctionsLogin extends SfCommand { 15 | public static description = 'Log in to a functions account.'; 16 | 17 | public static examples = [ 18 | 'sf login functions', 19 | 'sf login functions --jwt-file=./jwt.key --client-id XXXXXXXXXXXXXXX', 20 | ]; 21 | 22 | public static flags = { 23 | browser: Flags.string({ 24 | description: 'browser to open SSO with', 25 | options: [Browser.CHROME, Browser.FIREFOX, Browser.SAFARI], 26 | }), 27 | 'jwt-file': Flags.string({ 28 | char: 'f', 29 | description: 'file containing the JWT private key', 30 | }), 31 | 'client-id': Flags.string({ 32 | char: 'i', 33 | description: 'OAuth client ID (sometimes called the consumer key)', 34 | dependsOn: ['jwt-file'], 35 | }), 36 | }; 37 | 38 | public async run(): Promise { 39 | const { flags } = await this.parse(FunctionsLogin); 40 | return loginFunctions({ 41 | browser: flags.browser, 42 | clientId: flags['client-id'], 43 | jwtFile: flags['jwt-file'], 44 | }); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/commands/login/org.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { Flags } from '@oclif/core'; 9 | import { AnyJson } from '@salesforce/ts-types'; 10 | import { Messages } from '@salesforce/core'; 11 | 12 | import SfCommand from '../../sf-command'; 13 | import { Browser, loginOrg } from '../../utils'; 14 | 15 | Messages.importMessagesDirectory(__dirname); 16 | const messages = Messages.loadMessages('@salesforce/sf-demo', 'login.org'); 17 | 18 | export default class OrgLogin extends SfCommand { 19 | public static summary = messages.getMessage('summary'); 20 | public static description = messages.getMessage('description'); 21 | 22 | public static examples = messages.getMessages('examples'); 23 | 24 | public static flags = { 25 | alias: Flags.string({ 26 | summary: messages.getMessage('flags.alias.summary'), 27 | }), 28 | browser: Flags.string({ 29 | summary: messages.getMessage('flags.browser.summary'), 30 | description: messages.getMessage('flags.browser.description'), 31 | options: [Browser.CHROME, Browser.FIREFOX, Browser.SAFARI], 32 | }), 33 | 'client-id': Flags.string({ 34 | char: 'i', 35 | summary: messages.getMessage('flags.client-id.summary'), 36 | }), 37 | 'instance-url': Flags.string({ 38 | char: 'r', 39 | summary: messages.getMessage('flags.instance-url.summary'), 40 | description: messages.getMessage('flags.instance-url.description'), 41 | default: 'https://login.salesforce.com', 42 | }), 43 | 'set-default': Flags.boolean({ 44 | summary: messages.getMessage('flags.set-default.summary'), 45 | }), 46 | }; 47 | 48 | public async run(): Promise { 49 | const { flags } = await this.parse(OrgLogin); 50 | 51 | return loginOrg({ 52 | alias: flags.alias, 53 | browser: flags.browser, 54 | clientId: flags['client-id'], 55 | loginUrl: flags['instance-url'], 56 | }); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/commands/login/org/jwt.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { URL } from 'url'; 9 | import { Flags } from '@oclif/core'; 10 | import { AnyJson } from '@salesforce/ts-types'; 11 | import { Messages } from '@salesforce/core'; 12 | import SfCommand from '../../../sf-command'; 13 | 14 | import Aliases from '../../../configs/aliases'; 15 | 16 | Messages.importMessagesDirectory(__dirname); 17 | const messages = Messages.loadMessages('@salesforce/sf-demo', 'login.org.jwt'); 18 | 19 | export default class JWT extends SfCommand { 20 | public static summary = messages.getMessage('summary'); 21 | public static description = messages.getMessage('description'); 22 | 23 | public static examples = messages.getMessages('examples'); 24 | 25 | public static flags = { 26 | alias: Flags.string({ 27 | summary: messages.getMessage('flags.alias.summary'), 28 | }), 29 | 'audience-url': Flags.string({ 30 | summary: messages.getMessage('flags.audience-url.summary'), 31 | description: messages.getMessage('flags.audience-url.description'), 32 | }), 33 | 'client-id': Flags.string({ 34 | char: 'i', 35 | summary: messages.getMessage('flags.client-id.summary'), 36 | required: true, 37 | }), 38 | 'instance-url': Flags.string({ 39 | char: 'r', 40 | summary: messages.getMessage('flags.instance-url.summary'), 41 | description: messages.getMessage('flags.instance-url.description'), 42 | default: 'https://login.salesforce.com', 43 | }), 44 | 'jwt-key-file': Flags.string({ 45 | summary: messages.getMessage('flags.jwt-key-file.summary'), 46 | }), 47 | 'set-default': Flags.boolean({ 48 | summary: messages.getMessage('flags.set-default.summary'), 49 | }), 50 | username: Flags.string({ 51 | char: 'u', 52 | summary: messages.getMessage('flags.username.summary'), 53 | required: true, 54 | }), 55 | }; 56 | 57 | public async run(): Promise { 58 | const { flags, args } = await this.parse(JWT); 59 | 60 | const domain = new URL(flags['login-url']).host; 61 | const user = flags.username; 62 | let status = `Logged in as ${user}`; 63 | if (flags.alias) { 64 | status += `\n with alias ${flags.alias}`; 65 | const aliases = await Aliases.create({}); 66 | aliases.set(flags.alias, user); 67 | await aliases.write(); 68 | } 69 | if (flags['client-id']) { 70 | status += `\n with connected app ${flags['client-id']}`; 71 | } 72 | this.log(status); 73 | return { flags, args, domain, user }; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/commands/logout.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { Messages } from '@salesforce/core'; 9 | import { AnyJson } from '@salesforce/ts-types'; 10 | 11 | import SfCommand from '../sf-command'; 12 | import { logout } from '../utils'; 13 | 14 | Messages.importMessagesDirectory(__dirname); 15 | const messages = Messages.loadMessages('@salesforce/sf-demo', 'logout'); 16 | 17 | export default class Logout extends SfCommand { 18 | public static description = messages.getMessage('summary'); 19 | 20 | public async run(): Promise { 21 | const { args } = await this.parse(Logout); 22 | await logout(); 23 | 24 | return { args }; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/commands/logout/org.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { Flags } from '@oclif/core'; 9 | import { Messages } from '@salesforce/core'; 10 | import { AnyJson } from '@salesforce/ts-types'; 11 | 12 | import SfCommand from '../../sf-command'; 13 | import { logout } from '../../utils'; 14 | 15 | Messages.importMessagesDirectory(__dirname); 16 | const messages = Messages.loadMessages('@salesforce/sf-demo', 'logout.org'); 17 | 18 | export default class LogoutOrg extends SfCommand { 19 | public static summary = messages.getMessage('summary'); 20 | 21 | public static examples = messages.getMessages('examples'); 22 | 23 | public static flags = { 24 | 'target-org': Flags.string({ 25 | summary: messages.getMessage('flags.target-org.summary'), 26 | char: 't', 27 | }), 28 | }; 29 | 30 | public async run(): Promise { 31 | const { flags } = await this.parse(LogoutOrg); 32 | await logout(flags['target-org']); 33 | 34 | return { flags }; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/commands/package/package.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import SfCommand from '../../sf-command'; 9 | 10 | export default class Package extends SfCommand { 11 | public static description = 'Placeholder topic'; 12 | 13 | public static examples = ['sf package ...']; 14 | 15 | public async run(): Promise { 16 | this.log('This is a placeholder topic for the package plugin...'); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/commands/project/deploy.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { Flags } from '@oclif/core'; 9 | import { Duration, sleep } from '@salesforce/kit'; 10 | import { AnyJson } from '@salesforce/ts-types'; 11 | import { cli } from 'cli-ux'; 12 | import { cyan, green, red } from 'chalk'; 13 | import { prompt, Answers } from 'inquirer'; 14 | 15 | import { Messages } from '@salesforce/core'; 16 | import SfCommand from '../../sf-command'; 17 | import { Deployer, Deployers } from '../../project'; 18 | import { Environment } from '../../configs/environments'; 19 | import { generateTableChoices } from '../../utils'; 20 | 21 | Messages.importMessagesDirectory(__dirname); 22 | const messages = Messages.loadMessages('@salesforce/sf-demo', 'project.deploy'); 23 | 24 | export default class ProjectDeploy extends SfCommand { 25 | public static summary = messages.getMessage('summary'); 26 | public static description = messages.getMessage('description'); 27 | 28 | public static examples = ['sf project deploy', 'sf project deploy --target-env=devhub']; 29 | 30 | public static flags = { 31 | directory: Flags.string({ 32 | description: 'directory to deploy', 33 | }), 34 | 'target-env': Flags.string({ 35 | description: 'set ', 36 | multiple: true, 37 | }), 38 | interactive: Flags.boolean({ 39 | summary: messages.getMessage('flags.interactive.summary'), 40 | }), 41 | }; 42 | 43 | public loadEnvironments(environmentNames: string[] = []): Environment[] { 44 | // Try to used passed in environments 45 | return environmentNames.length > 0 46 | ? environmentNames.map((envName) => { 47 | const env = this.environments.get(envName); 48 | if (!env) { 49 | throw new Error(`Unknown environment ${envName}`); 50 | } 51 | return env; 52 | }) 53 | : // Or load up all the connected values to prompt 54 | this.environments.values().filter((env) => env.connected); 55 | } 56 | 57 | public async run(): Promise { 58 | const { flags } = await this.parse(ProjectDeploy); 59 | 60 | if (!this.accounts.has('hub')) { 61 | process.exitCode = 1; 62 | this.log(red('You have not authorized any accounts. Please run "sf login" first.')); 63 | return {}; 64 | } 65 | 66 | cli.action.start('Analyzing project'); 67 | // Make it seem a little real. 68 | await sleep(Duration.milliseconds(400)); 69 | cli.action.stop(); 70 | 71 | let deployers: Deployer[] = []; 72 | 73 | // Get all possible deployments 74 | for (const deployer of Deployers) { 75 | deployers = [ 76 | ...deployers, 77 | ...(await deployer.analyze({ 78 | path: flags.directory, 79 | interactive: flags.interactive, 80 | environments: this.loadEnvironments(flags['target-env']), 81 | })), 82 | ]; 83 | } 84 | 85 | if (!flags.directory) { 86 | deployers = await this.promptUserToChoseApps(deployers); 87 | } 88 | 89 | if (deployers.length === 0) { 90 | this.log('Nothing to deploy.'); 91 | return; 92 | } 93 | 94 | // Allow deployers to get setup and ask questions if needed. 95 | for (const deployer of deployers) { 96 | await deployer.init(); 97 | await deployer.setup(); 98 | } 99 | 100 | this.log(); 101 | for (const deployer of deployers) { 102 | cli.action.start(`Deploying changes to ${deployer.getType()} ${cyan.bold(deployer.environment.name)}`); 103 | const message = await deployer.deploy(); 104 | await sleep(500); 105 | cli.action.stop(green('Deploy complete!')); 106 | this.log(`\n\n${message}\n\n`); 107 | } 108 | 109 | return {}; 110 | } 111 | 112 | public async promptUserToChoseApps(deployers: Deployer[]): Promise { 113 | // If the user didn't specify what they want to deploy, ask. 114 | const columns = { 115 | name: 'APP OR PACKAGE', 116 | type: 'TYPE', 117 | path: 'PATH', 118 | }; 119 | const options = deployers.map((deployer) => ({ 120 | name: deployer.appName, 121 | type: deployer.getType(), 122 | path: deployer.appPath, 123 | value: deployer, 124 | })); 125 | 126 | const responses = await prompt([ 127 | { 128 | name: 'chooseApps', 129 | message: 'Select apps and packages to deploy:', 130 | type: 'checkbox', 131 | choices: generateTableChoices(columns, options), 132 | }, 133 | ]); 134 | 135 | /* eslint-disable-next-line @typescript-eslint/no-unsafe-return */ 136 | return responses.chooseApps as Deployer[]; // .map(response => response); 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /src/commands/project/deploy/functions.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { Messages } from '@salesforce/core'; 9 | import SfCommand from '../../../sf-command'; 10 | 11 | Messages.importMessagesDirectory(__dirname); 12 | const messages = Messages.loadMessages('@salesforce/sf-demo', 'project.deploy.functions'); 13 | 14 | export default class ProjectDeployFunctions extends SfCommand { 15 | public static summary = messages.getMessage('summary'); 16 | 17 | public static examples = messages.getMessages('examples'); 18 | 19 | public async run(): Promise { 20 | this.log('Deploying function...'); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/commands/project/deploy/org.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { Flags } from '@oclif/core'; 9 | import { Duration, sleep } from '@salesforce/kit'; 10 | import { AnyJson, ensureString } from '@salesforce/ts-types'; 11 | import { cli } from 'cli-ux'; 12 | import { cyan, green } from 'chalk'; 13 | 14 | import { Messages } from '@salesforce/core'; 15 | import SfCommand from '../../../sf-command'; 16 | import { Environment } from '../../../configs/environments'; 17 | import { SalesforceOrgDeployer } from '../../../project/sf-deployer'; 18 | 19 | Messages.importMessagesDirectory(__dirname); 20 | const messages = Messages.loadMessages('@salesforce/sf-demo', 'project.deploy.org'); 21 | 22 | export default class ProjectDeployOrg extends SfCommand { 23 | public static summary = messages.getMessage('summary'); 24 | public static description = messages.getMessage('description'); 25 | public static examples = messages.getMessages('examples'); 26 | 27 | public static flags = { 28 | 'check-only': Flags.boolean({ 29 | char: 'c', 30 | summary: messages.getMessage('flags.check-only.summary'), 31 | description: messages.getMessage('flags.check-only.description'), 32 | }), 33 | 'deploy-dir': Flags.string({ 34 | char: 'd', 35 | summary: messages.getMessage('flags.deploy-dir.summary'), 36 | description: messages.getMessage('flags.deploy-dir.description'), 37 | multiple: true, 38 | }), 39 | 'force-overwrite': Flags.boolean({ 40 | summary: messages.getMessage('flags.force-overwrite.summary'), 41 | }), 42 | 'ignore-errors': Flags.boolean({ 43 | summary: messages.getMessage('flags.ignore-errors.summary'), 44 | description: messages.getMessage('flags.ignore-errors.description'), 45 | }), 46 | 'ignore-warnings': Flags.boolean({ 47 | summary: messages.getMessage('flags.ignore-warnings.summary'), 48 | description: messages.getMessage('flags.ignore-warnings.description'), 49 | }), 50 | metadata: Flags.string({ 51 | char: 'm', 52 | summary: messages.getMessage('flags.metadata.summary'), 53 | multiple: true, 54 | }), 55 | manifest: Flags.string({ 56 | char: 'x', 57 | summary: messages.getMessage('flags.manifest.summary'), 58 | description: messages.getMessage('flags.manifest.description'), 59 | }), 60 | 'run-tests': Flags.string({ 61 | summary: messages.getMessage('flags.run-tests.summary'), 62 | }), 63 | 'single-package': Flags.boolean({ 64 | summary: messages.getMessage('flags.single-package.summary'), 65 | description: messages.getMessage('flags.single-package.description'), 66 | }), 67 | 'soap-deploy': Flags.boolean({ 68 | summary: messages.getMessage('flags.soapdeploy.summary'), 69 | description: messages.getMessage('flags.soapdeploy.description'), 70 | }), 71 | 'test-level': Flags.enum({ 72 | options: ['NoTestRun', 'RunSpecifiedTests', 'RunLocalTests', 'RunAllTestsInOrg'], 73 | summary: messages.getMessage('flags.test-level.summary'), 74 | description: messages.getMessage('flags.test-level.description'), 75 | }), 76 | 'target-env': Flags.string({ 77 | description: 'environment you want to deploy to', 78 | required: true, 79 | }), 80 | 'validated-deploy-request-id': Flags.string({ 81 | summary: messages.getMessage('flags.validated-deploy-request-id.summary'), 82 | description: messages.getMessage('flags.validated-deploy-request-id.description'), 83 | }), 84 | wait: Flags.integer({ 85 | summary: messages.getMessage('flags.wait.summary'), 86 | description: messages.getMessage('flags.wait.description'), 87 | }), 88 | 'zip-file': Flags.string({ 89 | summary: messages.getMessage('flags.zip-file.summary'), 90 | description: messages.getMessage('flags.zip-file.description'), 91 | }), 92 | }; 93 | 94 | public loadEnvironment(targetEnv: string): Environment { 95 | const environmentName = ensureString(this.aliases.get(targetEnv) || targetEnv); 96 | const env = this.environments.getContents()[environmentName] as Environment; 97 | if (!env) { 98 | throw new Error(`Unknown environment ${environmentName}`); 99 | } 100 | return env; 101 | } 102 | 103 | public async run(): Promise { 104 | const { flags } = await this.parse(ProjectDeployOrg); 105 | 106 | cli.action.start('Analyzing project'); 107 | // Make it seem a little real. 108 | await sleep(Duration.milliseconds(400)); 109 | cli.action.stop(); 110 | 111 | const environment = this.loadEnvironment(flags['target-env']); 112 | const flagsSpecified = flags['deploy-dir'] || flags.manifest || flags.metadata; 113 | const deployers = flagsSpecified 114 | ? await SalesforceOrgDeployer.analyze({ path: '', interactive: false, environments: [environment] }) 115 | : await SalesforceOrgDeployer.analyze({ 116 | path: 'force-app', 117 | interactive: false, 118 | environments: [environment], 119 | }); 120 | 121 | for (const deployer of deployers) { 122 | await deployer.init(); 123 | await deployer.setup(); 124 | if (flagsSpecified) { 125 | let changes = ''; 126 | 127 | if (flags['deploy-dir']) changes += `\n - directories: ${flags['deploy-dir'].join(', ')}`; 128 | if (flags.metadata) changes += `\n - metadata: ${flags.metadata.join(', ')}`; 129 | if (flags.manifest) changes += `\n - manifest: ${flags.manifest}`; 130 | this.log( 131 | `The following changes will be deployed to ${deployer.getType()} ${cyan.bold( 132 | deployer.environment.name 133 | )}: ${changes}\n` 134 | ); 135 | } else { 136 | this.log( 137 | `The following changes will be deployed to ${deployer.getType()} ${cyan.bold(deployer.environment.name)}` 138 | ); 139 | } 140 | await sleep(500); 141 | cli.action.start('Deploying'); 142 | const message = await deployer.deploy(); 143 | await sleep(500); 144 | cli.action.stop(green('Deploy complete!')); 145 | this.log(`\n\n${message}\n\n`); 146 | } 147 | return {}; 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /src/commands/project/retrieve.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { Flags } from '@oclif/core'; 9 | import { Messages } from '@salesforce/core'; 10 | import SfCommand from '../../sf-command'; 11 | 12 | Messages.importMessagesDirectory(__dirname); 13 | const messages = Messages.loadMessages('@salesforce/sf-demo', 'project.retrieve'); 14 | 15 | export default class ProjectRetrieve extends SfCommand { 16 | public static summary = messages.getMessage('summary'); 17 | public static description = messages.getMessage('description'); 18 | 19 | public static flags = { 20 | interactive: Flags.boolean({ 21 | summary: messages.getMessage('flags.interactive.summary'), 22 | }), 23 | }; 24 | 25 | public async run(): Promise { 26 | this.log('Retrieving project...'); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/commands/project/retrieve/org.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { Messages } from '@salesforce/core'; 9 | import SfCommand from '../../../sf-command'; 10 | 11 | Messages.importMessagesDirectory(__dirname); 12 | const messages = Messages.loadMessages('@salesforce/sf-demo', 'project.retrieve.org'); 13 | 14 | export default class ProjectRetrieveOrg extends SfCommand { 15 | public static summary = messages.getMessage('summary'); 16 | public static description = messages.getMessage('description'); 17 | public static examples = messages.getMessages('examples'); 18 | 19 | public async run(): Promise { 20 | this.log('Retrieving org...'); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/commands/reset.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { AnyJson } from '@salesforce/ts-types'; 9 | import { fs } from '@salesforce/core'; 10 | import SfCommand from '../sf-command'; 11 | import { CLI_CONFIG_PATH } from '../configs/constants'; 12 | 13 | export default class JWT extends SfCommand { 14 | public static description = 'Reset data created by this CLI.'; 15 | 16 | public async run(): Promise { 17 | await fs.rmdir(CLI_CONFIG_PATH, { recursive: true }); 18 | this.log(`Cleaned ${CLI_CONFIG_PATH}`); 19 | return {}; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/commands/run/apex.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { Messages } from '@salesforce/core'; 9 | import SfCommand from '../../sf-command'; 10 | 11 | Messages.importMessagesDirectory(__dirname); 12 | const messages = Messages.loadMessages('@salesforce/sf-demo', 'run.apex'); 13 | 14 | export default class RunApex extends SfCommand { 15 | public static summary = messages.getMessage('summary'); 16 | public static description = messages.getMessage('description'); 17 | 18 | public static examples = messages.getMessages('examples'); 19 | 20 | public async run(): Promise { 21 | this.log('Running code...'); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/commands/run/function.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import * as path from 'path'; 9 | import { Flags } from '@oclif/core'; 10 | import { sleep } from '@salesforce/kit'; 11 | import { AnyJson } from '@salesforce/ts-types'; 12 | import { green } from 'chalk'; 13 | import { cli } from 'cli-ux'; 14 | 15 | import { Messages } from '@salesforce/core'; 16 | import SfCommand from '../../sf-command'; 17 | 18 | Messages.importMessagesDirectory(__dirname); 19 | const messages = Messages.loadMessages('@salesforce/sf-demo', 'run.function'); 20 | 21 | export default class RunFunction extends SfCommand { 22 | public static summary = messages.getMessage('summary'); 23 | 24 | public static examples = [ 25 | 'sf run function -u http://localhost:8080 (http://localhost:8080/) -p \'{"id": 12345}\'', 26 | "sf run function -u http://localhost:8080 (http://localhost:8080/) -p '@file.json'", 27 | 'echo \'{"id": 12345}\' | sf run function -u http://localhost:8080 (http://localhost:8080/)', 28 | 'sf run function -u http://localhost:8080 (http://localhost:8080/) -p \'{"id": 12345}\' --structured', 29 | ]; 30 | 31 | public static flags = { 32 | headers: Flags.string({ 33 | description: 'Set headers of payload request', 34 | char: 'h', 35 | }), 36 | url: Flags.string({ 37 | description: 'the local URL endpoint of the Function to be invoked', 38 | char: 'l', 39 | }), 40 | payload: Flags.string({ 41 | char: 'p', 42 | description: 'The data to send to the function. Also accepts @file.txt format', 43 | }), 44 | structured: Flags.boolean({ 45 | description: 'Send data as JSON', 46 | }), 47 | }; 48 | 49 | public async run(): Promise { 50 | const { flags } = await this.parse(RunFunction); 51 | if (!path.dirname(process.cwd()).endsWith('functions')) { 52 | throw new Error('This command must be run from a functions directory'); 53 | } 54 | cli.action.start('Initializing context'); 55 | await sleep(500); 56 | cli.action.stop(green('done')); 57 | if (flags.url) { 58 | cli.action.start(`POST: ${flags.url}`); 59 | await sleep(1000); 60 | cli.action.stop(green('200')); 61 | } 62 | 63 | if (flags.payload) { 64 | this.log(JSON.stringify({ done: true, totalSize: 0, records: [] })); 65 | } 66 | return {}; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/commands/run/function/start.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | import * as path from 'path'; 8 | import { Flags } from '@oclif/core'; 9 | import { sleep } from '@salesforce/kit'; 10 | import { AnyJson } from '@salesforce/ts-types'; 11 | import { green } from 'chalk'; 12 | 13 | import { Messages } from '@salesforce/core'; 14 | import SfCommand from '../../../sf-command'; 15 | 16 | Messages.importMessagesDirectory(__dirname); 17 | const messages = Messages.loadMessages('@salesforce/sf-demo', 'run.function.start'); 18 | 19 | export default class RunFunctionStart extends SfCommand { 20 | public static summary = messages.getMessage('summary'); 21 | 22 | public static examples = [ 23 | 'sf run function start', 24 | 'sf run function start -e VAR=VALUE', 25 | 'sf run function start --network host --no-pull --clear-cache --debug-port 9000', 26 | ]; 27 | 28 | public static flags = { 29 | 'debug-port': Flags.string({ 30 | description: 'Port for remote debugging', 31 | char: 'd', 32 | }), 33 | env: Flags.string({ 34 | description: 'Set environment variables (provided during build and run)', 35 | char: 'e', 36 | }), 37 | port: Flags.string({ 38 | description: 'Port for running the function', 39 | char: 'p', 40 | }), 41 | 'connected-org': Flags.string({ 42 | description: 'Username or alias for the connected org', 43 | char: 'o', 44 | }), 45 | verbose: Flags.boolean({ 46 | description: 'Output additional logs', 47 | char: 'v', 48 | }), 49 | builder: Flags.string({ 50 | description: 'Set custom builder image', 51 | }), 52 | 'clear-cache': Flags.boolean({ 53 | description: 'Clear associated cache before executing', 54 | }), 55 | network: Flags.string({ 56 | description: 57 | 'Connect and build containers to a network. This can be useful to build containers which require a local resource', 58 | }), 59 | 'no-pull': Flags.boolean({ 60 | description: 'Skip pulling builder image before use', 61 | }), 62 | }; 63 | 64 | public async run(): Promise { 65 | if (!path.dirname(process.cwd()).endsWith('functions')) { 66 | throw new Error('This command must be run from a functions directory'); 67 | } 68 | 69 | const functionName = path.basename(process.cwd()); 70 | 71 | this.log(`${green('Building')} ${functionName}`); 72 | await sleep(1000); 73 | this.mockLogs(); 74 | 75 | return {}; 76 | } 77 | 78 | public mockLogs(): void { 79 | this.log(`20: Pulling from heroku/buildpacks 80 | Digest: sha256:ffcbca462c777cecf7b31081224904bf069f62067460d4fa62f8ac4b3ed077c8 81 | Status: Image is up to date for heroku/buildpacks:20 82 | 20: Pulling from heroku/pack 83 | Digest: sha256:1becdc661d667b0670d63a33b37eeec347cc24665f348ede6dfa26fdb9d976a0 84 | Status: Image is up to date for heroku/pack:20 85 | ===> DETECTING 86 | ======== Output: heroku/ruby@0.0.1 ======== 87 | no 88 | err: heroku/ruby@0.0.1 (1) 89 | 3 of 4 buildpacks participating 90 | heroku/nodejs-engine 0.7.3 91 | heroku/nodejs-npm 0.4.3 92 | heroku/nodejs-function-invoker 0.1.5 93 | ===> ANALYZING 94 | Restoring metadata for "heroku/nodejs-engine:nodejs" from app image 95 | Restoring metadata for "heroku/nodejs-engine:toolbox" from cache 96 | Restoring metadata for "heroku/nodejs-function-invoker:opt" from app image 97 | Restoring metadata for "heroku/nodejs-function-invoker:sf-fx-runtime-nodejs" from app image 98 | ===> RESTORING 99 | Restoring data for "heroku/nodejs-engine:nodejs" from cache 100 | Restoring data for "heroku/nodejs-engine:toolbox" from cache 101 | ===> BUILDING 102 | [INFO] Node.js Buildpack 103 | [INFO] Setting NODE_ENV to production 104 | [INFO] Installing toolbox 105 | [Installing Node] 106 | [INFO] Getting Node version 107 | [INFO] Resolving Node version 108 | [INFO] Reusing Node v14.17.0 109 | [Parsing package.json] 110 | [INFO] Parsing package.json 111 | [INFO] Using npm v6.14.13 from Node 112 | [INFO] Installing node modules 113 | npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@~2.3.1 (node_modules/chokidar/node_modules/fsevents): 114 | npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@2.3.2: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"}) 115 | audited 221 packages in 7.399s 116 | found 0 vulnerabilities 117 | up to date in 0.527s 118 | found 0 vulnerabilities 119 | [INFO] Successfully pruned devdependencies! 120 | [Installing Node.js function runtime] 121 | [INFO] Starting download of function runtime 122 | [INFO] Download of function runtime successful 123 | npm WARN deprecated request@2.88.2: request has been deprecated, see https://github.com/request/request/issues/3142 124 | npm WARN deprecated har-validator@5.1.5: this library is no longer supported 125 | /layers/heroku_nodejs-function-invoker/sf-fx-runtime-nodejs/bin/sf-fx-runtime-nodejs -> /layers/heroku_nodejs-function-invoker/sf-fx-runtime-nodejs/lib/node_modules/sf-fx-runtime-nodejs/bin/invoke.js 126 | > dtrace-provider@0.6.0 install /layers/heroku_nodejs-function-invoker/sf-fx-runtime-nodejs/lib/node_modules/sf-fx-runtime-nodejs/node_modules/dtrace-provider 127 | > node scripts/install.js 128 | > core-js@3.12.1 postinstall /layers/heroku_nodejs-function-invoker/sf-fx-runtime-nodejs/lib/node_modules/sf-fx-runtime-nodejs/node_modules/core-js 129 | > node -e "try{require('./postinstall')}catch(e){}" 130 | Thank you for using core-js ( https://github.com/zloirock/core-js ) for polyfilling JavaScript standard library! 131 | The project needs your help! Please consider supporting of core-js on Open Collective or Patreon: 132 | > https://opencollective.com/core-js 133 | > https://www.patreon.com/zloirock 134 | Also, the author of core-js ( https://github.com/zloirock ) is looking for a good job -) 135 | > core-js-pure@3.12.1 postinstall /layers/heroku_nodejs-function-invoker/sf-fx-runtime-nodejs/lib/node_modules/sf-fx-runtime-nodejs/node_modules/core-js-pure 136 | > node -e "try{require('./postinstall')}catch(e){}" 137 | + sf-fx-runtime-nodejs@0.1.0-ea 138 | added 242 packages from 300 contributors in 26.62s 139 | [INFO] Function runtime installation successful 140 | ===> EXPORTING 141 | Adding layer 'heroku/nodejs-engine:nodejs' 142 | Reusing layer 'heroku/nodejs-function-invoker:opt' 143 | Adding layer 'heroku/nodejs-function-invoker:sf-fx-runtime-nodejs' 144 | Adding 1/1 app layer(s) 145 | Reusing layer 'launcher' 146 | Adding layer 'config' 147 | Reusing layer 'process-types' 148 | Adding label 'io.buildpacks.lifecycle.metadata' 149 | Adding label 'io.buildpacks.build.metadata' 150 | Adding label 'io.buildpacks.project.metadata' 151 | Setting default process type 'web' 152 | Saving fn1... 153 | *** Images (fdd9373a1b02): 154 | fn1 155 | Adding cache layer 'heroku/nodejs-engine:nodejs' 156 | Reusing cache layer 'heroku/nodejs-engine:toolbox' 157 | Starting fn1 158 | Running on port :8080 159 | Debugger running on port :9229 160 | Debugger listening on ws://0.0.0.0:9229/4099e75d-5919-4c12-8b18-ca11dc1095ce 161 | For help, see: https://nodejs.org/en/docs/inspector`); 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /src/commands/test/apex.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { Messages } from '@salesforce/core'; 9 | import SfCommand from '../../sf-command'; 10 | 11 | Messages.importMessagesDirectory(__dirname); 12 | const messages = Messages.loadMessages('@salesforce/sf-demo', 'test.apex'); 13 | 14 | export default class TestApex extends SfCommand { 15 | public static summary = messages.getMessage('summary'); 16 | public static description = messages.getMessage('description'); 17 | 18 | public static examples = messages.getMessages('examples'); 19 | 20 | public async run(): Promise { 21 | this.log('Testing code...'); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/commands/test/function.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { Messages } from '@salesforce/core'; 9 | import SfCommand from '../../sf-command'; 10 | 11 | Messages.importMessagesDirectory(__dirname); 12 | const messages = Messages.loadMessages('@salesforce/sf-demo', 'test.function'); 13 | 14 | export default class TestFunction extends SfCommand { 15 | public static summary = messages.getMessage('summary'); 16 | 17 | public async run(): Promise { 18 | this.log('Testing function...'); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/commands/usage.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { cli } from 'cli-ux'; 9 | import { Flags } from '@oclif/core'; 10 | 11 | import { Messages } from '@salesforce/core'; 12 | import SfCommand from '../sf-command'; 13 | 14 | Messages.importMessagesDirectory(__dirname); 15 | const messages = Messages.loadMessages('@salesforce/sf-demo', 'usage'); 16 | export default class Usage extends SfCommand { 17 | public static description = messages.getMessage('summary'); 18 | 19 | public static flags = { 20 | // TODO: Add cli.table.flags - https://github.com/oclif/cli-ux#clitable 21 | json: Flags.string({ 22 | description: 'format output as json', 23 | }), 24 | }; 25 | 26 | public async run(): Promise { 27 | cli.table( 28 | [ 29 | { Name: 'Active Scratch Orgs', Remaining: '500', Max: '500' }, 30 | { Name: 'Daily Scratch Orgs', Remaining: '1000', Max: '1000' }, 31 | { Name: 'Developer Sandboxes', Remaining: '4', Max: '10' }, 32 | { Name: 'Partial Sandboxes', Remaining: '2', Max: '5' }, 33 | { Name: 'Full Sandboxes', Remaining: '2', Max: '2' }, 34 | { Name: 'Function Compute Spaces', Remaining: '1', Max: '1' }, 35 | ], 36 | { 37 | Name: {}, 38 | Remaining: {}, 39 | Max: {}, 40 | }, 41 | { 42 | /* TODO add cli.table.flags */ 43 | } 44 | ); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/commands/whoami.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { Messages } from '@salesforce/core'; 9 | import { AnyJson } from '@salesforce/ts-types'; 10 | import { green } from 'chalk'; 11 | import SfCommand from '../sf-command'; 12 | 13 | Messages.importMessagesDirectory(__dirname); 14 | const messages = Messages.loadMessages('@salesforce/sf-demo', 'whoami'); 15 | 16 | export default class WhoAmI extends SfCommand { 17 | public static description = messages.getMessage('summary'); 18 | 19 | public async run(): Promise { 20 | const hub = this.accounts.get('hub'); 21 | const heroku = this.accounts.get('heroku'); 22 | 23 | if (this.accounts.values().length === 0 && this.environments.values().length === 0) { 24 | this.log('No information found. Please login or connect to an environement first.'); 25 | } else { 26 | const mainUser = hub?.user || heroku?.user || this.environments.entries()[0][0]; 27 | this.log(`Hello ${green(mainUser)} 👋 28 | 29 | Currently, you are... 30 | - linked to ${this.accounts.values().length} accounts with access to ${this.accounts 31 | .values() 32 | .reduce((sum, account) => (account.environments?.length || 0) + sum, 0)} remote Enviornments. 33 | - connected to ${this.environments.values().length} environments. 34 | 35 | Think of all the information we could provide here! 36 | `); 37 | } 38 | 39 | return {}; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/configs/account.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { join } from 'path'; 9 | import { ConfigFile } from '@salesforce/core'; 10 | import { Dictionary, Optional } from '@salesforce/ts-types'; 11 | import { CLI_CONFIG_PATH } from './constants'; 12 | 13 | export type Account = { 14 | user: string; 15 | expires?: number; 16 | environments: string[]; 17 | }; 18 | 19 | export default class Accounts extends ConfigFile> { 20 | public static instance: Accounts; 21 | 22 | public static getInstance(): Accounts { 23 | if (!this.instance) { 24 | this.instance = new Accounts({}); 25 | this.instance.readSync(); 26 | } 27 | return this.instance; 28 | } 29 | 30 | public static getFileName(): string { 31 | return 'accounts.json'; 32 | } 33 | 34 | public getPath(): string { 35 | return join(CLI_CONFIG_PATH, Accounts.getFileName()); 36 | } 37 | 38 | public get(key: string): Optional { 39 | return super.get(key) as Optional; 40 | } 41 | 42 | public set(key: string, value: Account): Optional { 43 | return super.set(key, value) as unknown as Optional; 44 | } 45 | 46 | public unset(key: string): boolean { 47 | return super.unset(key); 48 | } 49 | 50 | public entries(): Array<[string, Account]> { 51 | return super.entries() as Array<[string, Account]>; 52 | } 53 | 54 | public values(): Account[] { 55 | return super.values() as Account[]; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/configs/aliases.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { join } from 'path'; 9 | import { ConfigFile } from '@salesforce/core'; 10 | import { Dictionary } from '@salesforce/ts-types'; 11 | import { CLI_CONFIG_PATH } from './constants'; 12 | 13 | export default class Aliases extends ConfigFile> { 14 | public static instance: Aliases; 15 | 16 | public static getInstance(): Aliases { 17 | if (!this.instance) { 18 | this.instance = new Aliases({}); 19 | this.instance.readSync(); 20 | } 21 | return this.instance; 22 | } 23 | 24 | public static getAliases(value: string): string[] { 25 | const aliases = this.getInstance(); 26 | return aliases.getKeysByValue(value); 27 | } 28 | 29 | public static set(key: string, value: string): void { 30 | const aliases = this.getInstance(); 31 | aliases.set(key, value); 32 | aliases.writeSync(); 33 | } 34 | 35 | public static getFileName(): string { 36 | return 'aliases.json'; 37 | } 38 | 39 | public getPath(): string { 40 | return join(CLI_CONFIG_PATH, Aliases.getFileName()); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/configs/constants.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { join } from 'path'; 9 | import { tmpdir } from 'os'; 10 | 11 | export const CLI_CONFIG_PATH = join(tmpdir(), 'clidoscope'); 12 | -------------------------------------------------------------------------------- /src/configs/environments.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { join } from 'path'; 9 | import { Dictionary, Optional } from '@salesforce/ts-types'; 10 | import { ConfigContents, ConfigFile, ConfigValue } from '@salesforce/core'; 11 | import { CLI_CONFIG_PATH } from './constants'; 12 | import Accounts from './account'; 13 | import Aliases from './aliases'; 14 | 15 | export type Environment = { 16 | name: string; 17 | aliases?: string[]; 18 | connected?: boolean; 19 | status?: string; 20 | type?: 'org' | 'compute'; 21 | context?: string; 22 | // Other auth information can be stored on the environement 23 | token?: string; 24 | orgId?: string; 25 | connectedOrg?: string; 26 | }; 27 | 28 | export type OrgEnvironment = { 29 | context?: 'scratch' | 'sandbox' | 'hub' | 'prod'; 30 | }; 31 | 32 | export type ComputeEnvironment = { 33 | context?: 'function' | 'heroku app'; 34 | }; 35 | 36 | export default class Environments extends ConfigFile> { 37 | public static instance: Environments; 38 | 39 | public static getInstance(): Environments { 40 | if (!this.instance) { 41 | this.instance = new Environments({}); 42 | this.instance.readSync(); 43 | } 44 | return this.instance; 45 | } 46 | 47 | public static async retrieveRemote(ignoreConnected = true): Promise { 48 | const accounts = Accounts.getInstance(); 49 | const enviornments = Environments.getInstance(); 50 | 51 | const remotes = accounts.entries().reduce((list, [accountName, account]) => { 52 | const type = accountName === 'heroku' ? 'compute' : 'org'; 53 | return [ 54 | ...list, 55 | ...account.environments.map((environmentName) => { 56 | const existingAccount = enviornments.get(environmentName); 57 | if (existingAccount) { 58 | return enviornments.get(environmentName); 59 | } 60 | return { 61 | name: environmentName, 62 | type, 63 | connected: false, 64 | status: 'Not Connected', 65 | context: 66 | accountName === 'heroku' 67 | ? environmentName.includes('heroku') 68 | ? 'heroku app' 69 | : 'functions' 70 | : environmentName.includes('scratch') 71 | ? 'scratch' 72 | : 'sandbox', 73 | } as Environment; 74 | }), 75 | ]; 76 | }, [] as Environment[]); 77 | if (ignoreConnected) { 78 | return remotes.filter((env) => !env.connected); 79 | } 80 | return remotes; 81 | } 82 | 83 | public static async connect(environment: Environment): Promise { 84 | const enviornments = Environments.getInstance(); 85 | 86 | // Set status to connected 87 | environment.status = 'Connected'; 88 | environment.connected = true; 89 | 90 | enviornments.set(environment.name, environment); 91 | await enviornments.write(); 92 | } 93 | 94 | public static getFileName(): string { 95 | return 'environments.json'; 96 | } 97 | 98 | public getPath(): string { 99 | return join(CLI_CONFIG_PATH, Environments.getFileName()); 100 | } 101 | 102 | public get(name: string): Optional { 103 | const environement = super.get(name) as Environment; 104 | if (environement) { 105 | environement.aliases = Aliases.getAliases(name); 106 | } 107 | return environement; 108 | } 109 | 110 | public set(name: string, value: Environment): Environment { 111 | return super.set(name, value) as unknown as Environment; 112 | } 113 | 114 | public unset(name: string): boolean { 115 | return super.unset(name); 116 | } 117 | 118 | public entries(): Array<[string, Environment]> { 119 | const entries = super.entries() as Array<[string, Environment]>; 120 | entries.forEach(([, env]) => (env.aliases = Aliases.getAliases(env.name))); 121 | return entries; 122 | } 123 | 124 | public values(): Environment[] { 125 | return super.values() as Environment[]; 126 | } 127 | 128 | protected setMethod(contents: ConfigContents, key: string, value?: ConfigValue): void { 129 | contents[key] = value; 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /src/hooks/readme.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { Hook, Interfaces } from '@oclif/core'; 9 | 10 | /** 11 | * A hook that runs before every command 12 | */ 13 | const hook: Hook.Init = async function (options: Interfaces.Hooks['init']): Promise { 14 | // this.config. 15 | if (options.id === 'readme') { 16 | this.config.commands.forEach((cmd) => { 17 | cmd.id = cmd.id.replace(/:/g, ' '); 18 | }); 19 | } 20 | }; 21 | 22 | export default hook; 23 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | export = {}; 9 | -------------------------------------------------------------------------------- /src/project/deployer.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { cyan } from 'chalk'; 9 | import { Answers, prompt, Separator } from 'inquirer'; 10 | import Environments, { Environment } from '../configs/environments'; 11 | import { generateTableChoices } from '../utils'; 12 | 13 | /* eslint-disable @typescript-eslint/no-unused-vars */ 14 | 15 | export type DeployerOptions = { 16 | path: string; 17 | interactive: boolean; 18 | environments: Environment[]; 19 | }; 20 | 21 | export abstract class Deployer { 22 | public environment: Environment; 23 | 24 | public constructor( 25 | /** 26 | * Name of the package or app that will be deployed 27 | */ 28 | public appName: string, 29 | /** 30 | * Path to the package or app that will be deployed 31 | */ 32 | public appPath: string, 33 | protected options: DeployerOptions 34 | ) { 35 | this.options.environments = this.options.environments.filter((env) => env.type === this.getEnvironmentType()); 36 | } 37 | 38 | public static async analyze(options: DeployerOptions): Promise { 39 | return await Promise.resolve([] as Deployer[]); 40 | } 41 | 42 | public getContextType(): string | undefined { 43 | return undefined; 44 | } 45 | 46 | public async init(): Promise { 47 | if (!this.options.interactive) { 48 | this.environment = this.options.environments[0]; 49 | return; 50 | } 51 | 52 | let question = 'Deploy changes for ' + cyan.bold(this.appName) + ' to:'; 53 | let response: Answers; 54 | 55 | // Select a valid environment from the user passed in environments 56 | if (this.options.environments.length > 0) { 57 | const columns = { 58 | alias: 'ALIAS', 59 | type: 'TYPE', 60 | name: 'NAME', 61 | }; 62 | 63 | const choices = this.options.environments.map((environment) => ({ 64 | alias: environment.aliases?.join(', ') || '', 65 | type: environment.context, 66 | name: environment.name, 67 | value: environment.name, 68 | })); 69 | 70 | response = await prompt([ 71 | { 72 | name: 'environment', 73 | message: question, 74 | type: 'list', 75 | loop: false, 76 | pageSize: 10, 77 | choices: generateTableChoices(columns, choices, false), 78 | }, 79 | ]); 80 | this.environment = this.options.environments.find((environement) => environement.name === response.environment); 81 | } 82 | // If the user didn't pass any in or there are no connected environments, ask if we should connect to one 83 | else { 84 | const columns = { 85 | name: 'ENVIRONMENT NAME', 86 | }; 87 | 88 | // Connected environments would have been set by the deployer. So just look at unconnected environments 89 | const remotes = (await Environments.retrieveRemote()).filter((environment) => { 90 | const isContext = this.getContextType() ? this.getContextType() === environment.context : true; 91 | const isType = environment.type === this.getEnvironmentType(); 92 | return isContext && isType; 93 | }); 94 | 95 | let choices; 96 | 97 | if (remotes.length > 0) { 98 | console.log(`\n\nNo connected ${cyan.dim(this.getEnvironmentType())} envirnments found.\n\n`); 99 | question = `Select a remote enviornment to connect and deploy changes for ${cyan.bold( 100 | this.appName 101 | )} to or login to a new environment.`; 102 | choices = remotes.map((environment) => ({ 103 | name: environment.name, 104 | value: environment.name, 105 | })); 106 | } 107 | 108 | const responses = await prompt([ 109 | { 110 | name: 'environment', 111 | message: question, 112 | type: 'list', 113 | loop: false, 114 | pageSize: 10, 115 | choices: [ 116 | ...generateTableChoices(columns, choices), 117 | new Separator('----'), 118 | { 119 | name: 'Connect to one using oauth?', 120 | value: '__CONNECT__', 121 | }, 122 | ], 123 | }, 124 | ]); 125 | 126 | if (responses.environment === '__CONNECT__') { 127 | const loginResponses = await prompt([ 128 | { 129 | name: 'loginUrl', 130 | message: 'Enter login url of environment to connect to:', 131 | }, 132 | ]); 133 | console.log(`\n\nOpening browser at ${loginResponses.loginUrl as string}... connected.\n\n`); 134 | console.log('The rest of this flow is not finished. Exiting...'); 135 | process.exit(); 136 | } 137 | 138 | // Set the enviornment to use TODO find in the environments in the opts or defaults 139 | this.environment = remotes.find((environment) => environment.name === responses.environment); 140 | await Environments.connect(this.environment); 141 | } 142 | } 143 | 144 | public async setup(): Promise { 145 | // Set next tick 146 | await Promise.resolve(); 147 | } 148 | 149 | public async deploy(): Promise { 150 | // Set next tick 151 | return await Promise.resolve(''); 152 | } 153 | 154 | /** 155 | * Get the name of the type of app to deploy. This should be the same for a single deployer class, but a static can't have abstract. 156 | */ 157 | public abstract getType(): string; 158 | 159 | public abstract getEnvironmentType(): string; 160 | } 161 | -------------------------------------------------------------------------------- /src/project/functions-deployer.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import * as path from 'path'; 9 | import { blue } from 'chalk'; 10 | // import { Answers, prompt } from 'inquirer'; 11 | import { fs } from '@salesforce/core'; 12 | import { Deployer, DeployerOptions } from './deployer'; 13 | 14 | export class FunctionsDeployer extends Deployer { 15 | public static type = 'Functions App'; 16 | 17 | public static async analyze(options: DeployerOptions): Promise { 18 | const deployers: Deployer[] = []; 19 | 20 | if (!options.path || options.path.includes('functions')) { 21 | const functionsPath = path.join('.', 'functions'); 22 | if (await fs.fileExists(functionsPath)) { 23 | const localFunctions = await fs.readdir(functionsPath); 24 | for (const localFunction of localFunctions) { 25 | deployers.push(new FunctionsDeployer(localFunction, `./functions/${localFunction}`, options)); 26 | } 27 | } else if (path.dirname(process.cwd()).endsWith('functions')) { 28 | const dirName = path.basename(process.cwd()); 29 | deployers.push(new FunctionsDeployer(dirName, `./functions/${dirName}`, options)); 30 | } else { 31 | deployers.push( 32 | new FunctionsDeployer('updateEstMonthlyPayments', './functions/updateEstMonthlyPayments', options) 33 | ); 34 | } 35 | } 36 | return deployers; 37 | } 38 | 39 | public getEnvironmentType(): string { 40 | return 'compute'; 41 | } 42 | 43 | public getContextType(): string { 44 | return 'functions'; 45 | } 46 | 47 | public getType(): string { 48 | return FunctionsDeployer.type; 49 | } 50 | 51 | public async setup(): Promise { 52 | // const responses = await prompt([ 53 | // { 54 | // name: 'functionEnviornment', 55 | // message: 56 | // 'Salesforce Functions must be deployed into a Functions App in order to access Salesforce data. \n\nDo you want to deploy ' + 57 | // cyan.bold(this.appName) + 58 | // ' to the default Functions App for your most recently used scratch org ' + 59 | // cyan.bold('Dreamhouse1') + 60 | // '?', 61 | // type: 'list', 62 | // loop: false, 63 | // pageSize: 4, 64 | // choices: [ 65 | // { 66 | // name: 'Yes, deploy to default app ' + cyan.bold('Dreamhouse1_appspace'), 67 | // value: 'default', 68 | // short: 'Deploy to ' + cyan.bold('Dreamhouse1_appspace'), 69 | // }, 70 | // { name: 'No, choose another existing destination app', value: 'another', short: 'Choose another app' }, 71 | // { name: 'Create a new destination app', value: 'new', short: 'Create new app' }, 72 | // ], 73 | // }, 74 | // ]); 75 | // // Set the enviornment to use TODO find in the environments in the opts or defaults 76 | // this.environment = { 77 | // /* eslint-disable-next-line @typescript-eslint/no-unsafe-assignment */ 78 | // name: responses.functionEnviornment, 79 | // connected: true, 80 | // type: 'compute', 81 | // context: 'functions', 82 | // }; 83 | } 84 | public async deploy(): Promise { 85 | return ( 86 | 'You may invoke your function manually with ' + 87 | blue(`sf event send ${this.appName}.Dreamhouse1_appspace --payload=DATA`) + 88 | ` or visit http://developer.salesforce.com//8shNsj8akba/functions/${this.appName} to view your function details` 89 | ); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/project/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { FunctionsDeployer } from './functions-deployer'; 9 | import { SalesforceDeployer } from './sf-deployer'; 10 | 11 | export { Deployer, DeployerOptions } from './deployer'; 12 | export { FunctionsDeployer } from './functions-deployer'; 13 | export { SalesforceDeployer } from './sf-deployer'; 14 | 15 | export const Deployers = [SalesforceDeployer, FunctionsDeployer]; 16 | -------------------------------------------------------------------------------- /src/project/sf-deployer.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { blue, cyan } from 'chalk'; 9 | import { Answers, prompt } from 'inquirer'; 10 | import { Deployer, DeployerOptions } from './deployer'; 11 | 12 | export class SalesforceDeployer extends Deployer { 13 | public static type = 'Salesforce App'; 14 | 15 | public static async analyze(options: DeployerOptions): Promise { 16 | const deployers: Deployer[] = []; 17 | if (!options.path || options.path.includes('force')) { 18 | deployers.push(new SalesforceDeployer('Dreamhouse', './force-app', options)); 19 | } 20 | return deployers; 21 | } 22 | 23 | public getEnvironmentType(): string { 24 | return 'org'; 25 | } 26 | 27 | public getType(): string { 28 | return SalesforceDeployer.type; 29 | } 30 | 31 | public async setup(): Promise { 32 | await prompt([ 33 | { 34 | name: 'tests', 35 | message: 'Select the test level you would like to run for ' + cyan.bold('Dreamhouse') + ':', 36 | type: 'list', 37 | loop: false, 38 | pageSize: 4, 39 | choices: [ 40 | { name: 'Run local tests', value: 'local', short: 'Run local tests' }, 41 | { name: 'Run specified tests', value: 'specified', short: 'Run specified tests' }, 42 | { name: 'Run all tests in environment', value: 'all', short: 'Run all tests in environment' }, 43 | { name: "Don't run tests", value: 'none', short: "Don't run tests" }, 44 | ], 45 | }, 46 | ]); 47 | } 48 | 49 | public async deploy(): Promise { 50 | return ( 51 | 'Open your Salesforce App in your browser with ' + 52 | blue('sf env open -u ' + this.environment.name) + 53 | ' or visit http://wise-koala-7i3w1u.lightning.force.com' 54 | ); 55 | } 56 | } 57 | 58 | export class SalesforceOrgDeployer extends SalesforceDeployer { 59 | public static async analyze(options: DeployerOptions): Promise { 60 | const deployers: Deployer[] = []; 61 | deployers.push(new SalesforceOrgDeployer('Dreamhouse', options.path, options)); 62 | return deployers; 63 | } 64 | 65 | public async setup(): Promise { 66 | // do nothing 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/sf-command.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { Command } from '@oclif/core'; 9 | 10 | import Accounts from './configs/account'; 11 | import Environments from './configs/environments'; 12 | import Aliases from './configs/aliases'; 13 | 14 | export default abstract class SfCommand extends Command { 15 | protected accounts = Accounts.getInstance(); 16 | protected environments = Environments.getInstance(); 17 | protected aliases = Aliases.getInstance(); 18 | } 19 | -------------------------------------------------------------------------------- /src/utils.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | import { URL } from 'url'; 9 | import { AnyJson, Dictionary, ensureString } from '@salesforce/ts-types'; 10 | import { Separator, ChoiceBase, ChoiceOptions } from 'inquirer'; 11 | import Accounts from './configs/account'; 12 | import Environments, { Environment } from './configs/environments'; 13 | import Aliases from './configs/aliases'; 14 | 15 | // eslint-disable-next-line no-shadow 16 | export enum Browser { 17 | SAFARI = 'safari', 18 | FIREFOX = 'firefox', 19 | CHROME = 'chrome', 20 | } 21 | 22 | export type LoginArgs = { 23 | browser?: string; 24 | expiresIn?: number; 25 | clientId?: string; 26 | alias?: string; 27 | loginUrl?: string; 28 | jwtFile?: string; 29 | }; 30 | 31 | export function generateOrgId(): string { 32 | function randIntBetween(min: number, max: number): number { 33 | return Math.floor(Math.random() * (max - min) + min); 34 | } 35 | 36 | function randomLetter(): string { 37 | const alphabet = 'abcdefghijklmnopqrstuvwxyz'; 38 | return alphabet[Math.floor(Math.random() * alphabet.length)].toUpperCase(); 39 | } 40 | 41 | const fourRandomLetters = [randomLetter(), randomLetter(), randomLetter(), randomLetter()].join(''); 42 | return `00${randomLetter()}${randIntBetween(1, 10)}00${randIntBetween(1, 10)}0000${fourRandomLetters}`; 43 | } 44 | 45 | export async function login( 46 | domain = 'https://login.salesforce.com', 47 | user: string, 48 | expires?: number 49 | ): Promise { 50 | const environments = Environments.getInstance(); 51 | const accounts = Accounts.getInstance(); 52 | 53 | if (domain.includes('heroku')) { 54 | accounts.set('heroku', { 55 | user, 56 | expires, 57 | // Set remote environments not connected too. 58 | environments: ['heroku-app-1', 'heroku-app-2', 'heroku-app-3'], 59 | }); 60 | } else { 61 | const hub = accounts.get('hub'); 62 | 63 | if (!hub && !user.includes('sandbox')) { 64 | // Set remote environments not connected too. 65 | accounts.set('hub', { 66 | user, 67 | environments: [ 68 | `${user}.scratch1`, 69 | `${user}.scratch2`, 70 | `${user}.scratch3`, 71 | `${user.replace('login', 'test')}.sandbox`, 72 | ], 73 | }); 74 | } 75 | 76 | // A heroku account doesn't show up as an enviornment, so only do for orgs. 77 | environments.set(user, { 78 | name: user, 79 | connected: true, 80 | status: 'Connected', 81 | type: 'org', 82 | orgId: generateOrgId(), 83 | // You could imagine a post auth step to get this sort of information from the enviornment. 84 | context: !user.includes('sandbox') ? 'hub' : 'sandbox', 85 | }); 86 | 87 | accounts.set('functions', { 88 | user, 89 | expires, 90 | // Set remote environments not connected too. 91 | environments: ['functions-env-1', 'functions-env-2', 'functions-env-3'], 92 | }); 93 | environments.set('functions-env-1', { 94 | name: 'functions-env-1', 95 | connected: true, 96 | status: 'Connected', 97 | type: 'compute', 98 | context: 'functions', 99 | connectedOrg: user, 100 | }); 101 | environments.set('functions-env-2', { 102 | name: 'functions-env-2', 103 | connected: true, 104 | status: 'Connected', 105 | type: 'compute', 106 | context: 'functions', 107 | connectedOrg: user, 108 | }); 109 | // environments.set('functions-env-3', { 110 | // name: 'functions-env-3', 111 | // connected: true, 112 | // status: 'Connected', 113 | // type: 'compute', 114 | // context: 'functions', 115 | // }); 116 | 117 | await environments.write(); 118 | } 119 | await accounts.write(); 120 | return environments.get(user); 121 | } 122 | 123 | export async function logout(user?: string): Promise { 124 | const environments = Environments.getInstance(); 125 | const accounts = Accounts.getInstance(); 126 | 127 | if (!user) { 128 | accounts.clear(); 129 | environments.clear(); 130 | } else { 131 | // TODO: Logout from specific user 132 | } 133 | await accounts.write(); 134 | await environments.write(); 135 | return true; 136 | } 137 | 138 | export async function loginOrg(args: LoginArgs): Promise { 139 | const environments = Environments.getInstance(); 140 | const aliases = Aliases.getInstance(); 141 | const browser = args.browser || 'browser'; 142 | const url = args.loginUrl || 'https://login.salesforce.com'; 143 | const loginUrl = (url.startsWith('http') ? url : `https://${url}`).replace(/\/$/, ''); 144 | 145 | if (!loginUrl.endsWith('salesforce.com')) { 146 | throw new Error('Salesforce CLI only supports logging into salesforce.com'); 147 | } 148 | 149 | console.log(`Opening ${browser} at ${loginUrl}...\n`); 150 | 151 | const domain = new URL(loginUrl).host; 152 | let user = `myuser-${domain}@mycompany.com`; 153 | 154 | // If this is the second time running login an an org, regerster it as a sandbox 155 | if (environments.get(user) || domain.includes('test')) { 156 | user += '.sandbox'; 157 | } 158 | 159 | let status = `Logged in as ${user}`; 160 | if (args.alias) { 161 | status += `\n with alias ${args.alias}`; 162 | 163 | aliases.set(args.alias, user); 164 | await aliases.write(); 165 | } 166 | if (args.clientId) { 167 | status += `\n with connected app ${args.clientId}`; 168 | } 169 | 170 | console.log(status); 171 | 172 | await login(domain, user, args.expiresIn); 173 | return { args, domain, user }; 174 | } 175 | 176 | export async function loginHeroku(args: LoginArgs): Promise { 177 | const environments = Environments.getInstance(); 178 | const aliases = Aliases.getInstance(); 179 | const browser = args.browser || 'browser'; 180 | const url = args.loginUrl || 'https://heroku.com'; 181 | const loginUrl = (url.startsWith('http') ? url : `https://${url}`).replace(/\/$/, ''); 182 | 183 | if (!loginUrl.endsWith('heroku.com')) { 184 | throw new Error('Salesforce CLI only supports logging into heroku.com'); 185 | } 186 | 187 | console.log(`Opening ${browser} at ${loginUrl}...\n`); 188 | 189 | const domain = new URL(loginUrl).host; 190 | let user = `myuser-${domain}@mycompany.com`; 191 | 192 | // If this is the second time running login an an org, regerster it as a sandbox 193 | if (environments.get(user) || domain.includes('test')) { 194 | user += '.sandbox'; 195 | } 196 | 197 | let status = `Logged in as ${user}`; 198 | if (args.alias) { 199 | status += `\n with alias ${args.alias}`; 200 | 201 | aliases.set(args.alias, user); 202 | await aliases.write(); 203 | } 204 | if (args.clientId) { 205 | status += `\n with connected app ${args.clientId}`; 206 | } 207 | 208 | console.log(status); 209 | 210 | await login(domain, user, args.expiresIn); 211 | return { args, domain, user }; 212 | } 213 | 214 | export async function loginFunctions(args: Partial): Promise { 215 | const environments = Environments.getInstance(); 216 | const browser = args.browser || 'browser'; 217 | const loginUrl = 'https://functions.salesforce.com'; 218 | 219 | console.log(`Opening ${browser} at ${loginUrl}...\n`); 220 | 221 | const domain = new URL(loginUrl).host; 222 | let user = `myuser-${domain}@mycompany.com`; 223 | 224 | // If this is the second time running login an an org, regerster it as a sandbox 225 | if (environments.get(user) || domain.includes('test')) { 226 | user += '.sandbox'; 227 | } 228 | 229 | let status = `Logged in as ${user}`; 230 | 231 | if (args.clientId) { 232 | status += `\n with connected app ${args.clientId}`; 233 | } 234 | console.log(status); 235 | 236 | await login(domain, user, args.expiresIn); 237 | return { args, domain, user }; 238 | } 239 | 240 | export function generateTableChoices( 241 | columns: Dictionary, 242 | choices: Array>, 243 | padForCheckbox = true 244 | ): ChoiceBase[] { 245 | const columnEntries = Object.entries(columns); 246 | const columnLengths = columnEntries.map( 247 | ([key, value]) => 248 | Math.max( 249 | value.length, 250 | ...choices.map( 251 | (option) => 252 | ensureString(option[key], `Type ${typeof option[key]} for ${key} in ${Object.keys(option).join(', ')}`) 253 | .length 254 | ) 255 | ) + (padForCheckbox ? 3 : 0) 256 | ); 257 | 258 | const choicesOptions: ChoiceBase[] = [ 259 | // Pad an extra 2 to account for checkbox 260 | new Separator(columnEntries.map(([, value], index) => value.padEnd(columnLengths[index] + 2, ' ')).join('')), 261 | ]; 262 | 263 | for (const meta of choices) { 264 | const name = columnEntries 265 | .map(([key], index) => ensureString(meta[key]).padEnd(columnLengths[index], ' ')) 266 | .join(''); 267 | const choice: ChoiceOptions = { name, value: meta.value, short: ensureString(meta.name) }; 268 | choicesOptions.push(choice); 269 | } 270 | return choicesOptions; 271 | } 272 | -------------------------------------------------------------------------------- /test/.eslintrc.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | 8 | module.exports = { 9 | extends: '../.eslintrc.js', 10 | // Allow describe and it 11 | env: { mocha: true }, 12 | rules: { 13 | // Allow assert style expressions. i.e. expect(true).to.be.true 14 | 'no-unused-expressions': 'off', 15 | 16 | // It is common for tests to stub out method. 17 | 18 | // Return types are defined by the source code. Allows for quick overwrites. 19 | '@typescript-eslint/explicit-function-return-type': 'off', 20 | // Mocked out the methods that shouldn't do anything in the tests. 21 | '@typescript-eslint/no-empty-function': 'off', 22 | // Easily return a promise in a mocked method. 23 | '@typescript-eslint/require-await': 'off', 24 | }, 25 | }; 26 | -------------------------------------------------------------------------------- /test/commands/noop.test.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, salesforce.com, inc. 3 | * All rights reserved. 4 | * Licensed under the BSD 3-Clause license. 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | -------------------------------------------------------------------------------- /test/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@salesforce/dev-config/tsconfig-test", 3 | "include": ["./**/*.ts"], 4 | "compilerOptions": { 5 | "skipLibCheck": true 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@salesforce/dev-config/tsconfig", 3 | "compilerOptions": { 4 | "outDir": "lib", 5 | "rootDir": "src", 6 | "skipLibCheck": true 7 | }, 8 | "include": ["./src/**/*.ts"] 9 | } 10 | --------------------------------------------------------------------------------