[RFC] Multiple (private) GAS targets: remotes
- Dominant language
- TypeScript
- Stars
- 5.8k
- Forks
- 510
- Avg merge
- 5h 27m
- Merged PRs (30d)
- 1
Description
Currently there can be only one "canonical" `scriptId` for a codebase to `push`, `pull`, `version` and `deploy` to. This becomes problematic in non-trivial setups ([#921](https://github.com/google/clasp/issues/921), [#987](https://github.com/google/clasp/issues/987)).
In preparation for improvements to the multi-developer workflow ([#921 (comment)](https://github.com/google/clasp/issues/921#issuecomment-1217019516)) I propose the introduction of multiple Apps Script targets within a project, analogous to [git remotes](https://git-scm.com/book/en/v2/Git-Basics-Working-with-Remotes).
Some of these 'remotes' can be shared and tracked by source control, like a staging or production environment, while others must stay private, such as an individual's testing setup.
### Usecases
- Separate development, staging and production environments.
- Avoid "communal project" setup for shared (open source) projects, like clasp's own tests ([#987](https://github.com/google/clasp/issues/987))
- Multi-developer workflow ([#921](https://github.com/google/clasp/issues/921#issuecomment-1217019516))
### Prior art
- [clasp-env](https://www.npmjs.com/package/clasp-env)
- [multi-clasp](https://www.npmjs.com/package/multi-clasp) & [multi-clasp2](https://www.npmjs.com/package/multi-clasp2)
- Design based on [git remote](https://git-scm.com/docs/git-remote)
- #625, which calls them "targets", doesn't propose private remotes and is more similar to git branches than remotes. In my humble opinion a mostly stateless remote-based mechanism would be more straightforward to use.
### Configuration
A remote is described by a `scriptId`, `projectId` and `parentId`. These are currently configured at the root of `.clasp.json`.
I propose to move these properties to a `remotes` array of the following structure:
```json
"remotes": [
{
"name": "development",
"scriptId": "...",
"projectId": "...",
"parentId": "..."
}
]
```
For backwards compatibility the old 'root keys' can be interpreted as a remote with the configured `defaultRemoteName` (see next section). This behavior could be deprecated and removed in the next major version. Combining the 'root keys' with the `remotes` option should throw an error.
#### Private remotes
Currently `.clasp.json` mixes shared "project structure" like `rootDir` and `filePushOrder` with possibly private "deployment target" configuration.
This means `.clasp.json` shouldn't be excluded from source control, but can't be shared either.
I propose adding the aforementioned `remotes` option to the private `.clasprc.json` as well. Remote names should be unique, a shared and private remote with the same cannot coexist. For simplicity a private `remotes` should be incompatible with the shared 'root keys' configuration.
This setup is analogous to `package.json` and `.npmrc`, where the first describes (shared) project structure and the latter (mostly) private configuration, including credentials.
I'd assume most remotes are intended to be private, so to avoid accidents most of the design is "private by default".
#### Supporting `.clasprc.json` settings
- `defaultRemote`: default remote for various commands, analogous to [`remote.pushDefault`](https://git-scm.com/docs/git-config#Documentation/git-config.txt-remotepushDefault).
- `defaultRemoteName`: default name for remote created by `create`, `clone` and legacy root keys, analogous to [`clone.defaultRemoteName`](https://git-scm.com/docs/git-config#Documentation/git-config.txt-clonedefaultRemoteName). Default value of "default".
### New command: `remote`
Manually manipulating `.clasp.json` like cavemen isn't a great experience, so I propose to add a `clasp remote` command analogous to [`git remote`](https://git-scm.com/docs/git-remote).
This command should have the following subcommands:
- `add `
- `list`
- `show [...]`
- `rename `
- `update [... ]`
- `remove [...]`
A detailed proposal for each of these subcommands can be found [here](https://gist.github.com/HoldYourWaffle/625bb6ed70dfb179642789a5c7f2376c#new-remote-command).
### Adjustments to existing commands
The following commands get a new positional `[remote]` argument at the start:
- `push` and `pull`
- `version` and `versions`
- `deploy`, `deployments` and `undeploy`
- `open`, `run`, `logs` and `apis`
This new argument is required, unless:
- `defaultRemote` is configured.
- `.clasp.json` still uses a 'root keys' remote. This should show a deprecation warning.
Note that this argument is required even if `remotes` contains just one entry. This avoids accidentally messing with a shared (production) remote if a developer forgets to set up their own private one.
Some commands need other and/or extra adjustments, a detailed overview can be found [here](https://gist.github.com/HoldYourWaffle/625bb6ed70dfb179642789a5c7f2376c#adjustments-to-other-commands).
### Other considerations
1. With this proposal `.clasp.json` explicitly only contains public information that should be tracked by version control. I'd propose to rename this file to `clasp.json` (with the necessary fallbacks to avoid a breaking change) to signal it's public nature, analogous to `package.json`, `tsconfig.json`, `vite.config.js` and similar shared configuration files.
2. The authentication settings currently in `.clasprc.json` are inherited from the home and parent directories. Should the same apply to `remotes`, `defaultRemote` and `defaultRemoteName`?
**Update 15-11-23:** Abandoned the ability for private remotes to override shared ones with the same name. This could lead to unintuitive behavior, (re)designing the commands in a way that avoids this proved too complicated.
Contributor guide
Assessment
This issue has not been assessed yet.