diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 574f665c4c..0f31d05a16 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -5,7 +5,7 @@ "LOG_LEVEL": "debug", "DAYTONA_SERVER_MODE": "development", "CGO_ENABLED": "0", - "DAYTONA_WS_ID": "" + "DAYTONA_TARGET_ID": "" }, "postCreateCommand": ".devcontainer/postcreate.sh", "postStartCommand": "git config --global --add safe.directory ${containerWorkspaceFolder}", diff --git a/.vscode/launch.json b/.vscode/launch.json index 8b084fb550..127c27de76 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -12,8 +12,8 @@ "program": "${workspaceFolder}/cmd/daytona", "console": "integratedTerminal", "env": { - "DAYTONA_WS_ID": "WS_ID", - "DAYTONA_WS_PROJECT_NAME": "PROJECT_NAME", + "DAYTONA_TARGET_ID": "TARGET_ID", + "DAYTONA_WORKSPACE_ID": "WORKSPACE_ID", "DAYTONA_SERVER_URL": "http://localhost:3986", "DAYTONA_SERVER_API_KEY": "1234567890", }, @@ -50,6 +50,22 @@ "DAYTONA_DEV": "1", "DAYTONA_CONFIG_DIR": "/home/daytona/.config/daytona-dev", } + }, + { + "name": "Runner", + "type": "go", + "request": "launch", + "mode": "debug", + "program": "${workspaceFolder}/cmd/daytona", + "console": "integratedTerminal", + "args": [ + "runner", + "serve" + ], + "env": { + "DAYTONA_DEV": "1", + "DAYTONA_RUNNER_CONFIG_DIR": "/home/daytona/.config/daytona-runner", + } } ] } \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4abbd97e74..64ddae180e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,6 +5,7 @@ The team at Daytona welcomes contributions from the community. There are many wa Thanks for taking the time to contribute! ❤️ > And if you like the project but don't have time to contribute, that's perfectly okay. There are other simple ways to support the project and show your appreciation, which we would greatly appreciate: +> > - Star the project > - Tweet about it > - Contribute to our [Docs](https://github.com/daytonaio/docs/) @@ -22,29 +23,31 @@ to [info@daytona.io](mailto:info@daytona.io). You might find things that can be improved while you are using Daytona. You can help by [submitting an issue](https://github.com/daytonaio/daytona/issues/new) when: -* A new feature or an enhancement to an existing feature will improve the utility or usability of Daytona. -* Daytona crashes, or you encounter a bug that can only be resolved by restarting Daytona. -* An error occurs that is unrecoverable, causes workspace integrity problems or loss, or generally prevents you from using a workspace. +- A new feature or an enhancement to an existing feature will improve the utility or usability of Daytona. +- Daytona crashes, or you encounter a bug that can only be resolved by restarting Daytona. +- An error occurs that is unrecoverable, causes workspace integrity problems or loss, or generally prevents you from using a workspace. Before creating a new issue, please confirm that an existing issue doesn't already exist. We will then take care of the issue as soon as possible. ## Participate in the Community + You can engage with our community by: -* Helping other users on [Daytona Community Slack](https://go.daytona.io/slack). -* Improving [documentation](https://github.com/daytonaio/docs/) -* Participating in general discussions about development and DevOps -* Authoring new Daytona Plugins and sharing those Plugins -* Authoring new dev containers and sharing examples +- Helping other users on [Daytona Community Slack](https://go.daytona.io/slack). +- Improving [documentation](https://github.com/daytonaio/docs/) +- Participating in general discussions about development and DevOps +- Authoring new Daytona Plugins and sharing those Plugins +- Authoring new dev containers and sharing examples ## Contributing Code + You can contribute to Daytona by: -* Enhancing current functionality -* Fixing bugs -* Adding new features and capabilities +- Enhancing current functionality +- Fixing bugs +- Adding new features and capabilities Before starting your contribution, especially for core features, we encourage you to reach out to us on [Slack](https://go.daytona.io/slack). This allows us to ensure that your proposed feature aligns with the project's roadmap and goals. Developers are the key to making Daytona the best tool it can be, and we value input from the community. @@ -72,11 +75,35 @@ Follow the following steps to ensure your contribution goes smoothly. Note: In some cases, we might decide that a PR should be closed without merging. We'll make sure to provide clear reasoning when this happens. +### Coding Style and Conventions + +To make the code base consistent, we follow a few guidelines and conventions listed below. + +It is possible that the code base does not currently comply with all these guidelines. +While working on a PR, if you see something that can be refactored to comply, go ahead, but keep in mind that we are not looking for massive PRs that only address that. + +API and service method conventions: + +1. Avoid using model names in service methods + - e.g. `Create` instead of `CreateTarget`, `Find` instead of `FindWorkspace` +1. Use model names in service methods for "sub-models" + - e.g. `ListPrebuilds` in `WorkspaceTemplateService` +1. Use appropriate verbs in the UI + - e.g. `Create API Key` instead of `Generate API Key` since the method is called `Create` +1. Refer to the table below for a connection between API and service methods + +| HTTP Method | Controller / Service / Store | +| ----------- | ---------------------------- | +| POST | Create or Update | +| DELETE | Delete | +| PUT | Save | +| GET | Find or List | + #### What Does Contributing Mean for You? Here is what being a contributor means for you: -* License all our contributions to the project under the Apache License, Version 2.0 -* Have the legal rights to license our contributions ourselves, or get permission to license them from our employers, clients, or others who may have them +- License all our contributions to the project under the Apache License, Version 2.0 +- Have the legal rights to license our contributions ourselves, or get permission to license them from our employers, clients, or others who may have them For more information, see the [README](README.md) and feel free to reach out to us on [Slack](https://go.daytona.io/slack). diff --git a/README.md b/README.md index e81007ff7d..e84d5e33b3 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,3 @@ -
- -
- - - Daytona logo - -
- -
-
[![Documentation](https://img.shields.io/github/v/release/daytonaio/docs?label=Docs&color=23cc71)](https://www.daytona.io/docs) @@ -16,72 +5,56 @@ [![Go Report Card](https://goreportcard.com/badge/github.com/daytonaio/daytona)](https://goreportcard.com/report/github.com/daytonaio/daytona) [![Issues - daytona](https://img.shields.io/github/issues/daytonaio/daytona)](https://github.com/daytonaio/daytona/issues) ![GitHub Release](https://img.shields.io/github/v/release/daytonaio/daytona) -
-[![Open Bounties](https://img.shields.io/endpoint?url=https%3A%2F%2Fconsole.algora.io%2Fapi%2Fshields%2Fdaytonaio%2Fbounties%3Fstatus%3Dopen)](https://console.algora.io/org/daytonaio/bounties?status=open) -[![Rewarded Bounties](https://img.shields.io/endpoint?url=https%3A%2F%2Fconsole.algora.io%2Fapi%2Fshields%2Fdaytonaio%2Fbounties%3Fstatus%3Dcompleted)](https://console.algora.io/org/daytonaio/bounties?status=completed) - -
- -Daytona - Dev environment manager that makes you 2x more productive | Product Hunt -Daytona - Dev environment manager that makes you 2x more productive | Product Hunt
+  -

The Open Source Development Environment Manager

-Set up a development environment on any infrastructure, with a single command. + + + + Daytona logo +
-
+

+ Set up a development environment on any infrastructure using a single command: +

+ +
+ +![Daytona Demo](/assets/images/daytona_demo.gif) + +

- Documentation - · - Report Bug - · - Request Feature - · - Join Our Slack - · - Twitter -

- -
+ Documentation · + Report Bug · + Request Feature · + Join Our Slack · + Connect On X +

+ +
+ +# Open Source Development Environment Manager +
+ +For detailed/manual setup steps click [here](https://www.daytona.io/docs/installation/installation/#installation) -## Features -* __Single Command__: Activate a fully configured development environment with a single command. -* __Runs everywhere__: spin up your development environment on any machine — whether it's local, remote, cloud-based, physical server, or a VM & any architecture x86 or ARM. -* __Configuration File Support__: Initially support for [dev container](https://containers.dev/), ability to expand to DevFile, Nix & Flox (Contributions welcome here!). -* __Prebuilds System__: Drastically improve environment setup times (Contributions welcome here!). -* __IDE Support__ : Seamlessly supports [VS Code](https://github.com/microsoft/vscode) & [JetBrains](https://www.jetbrains.com/remote-development/gateway/) locally, ready to use without configuration. Includes a built-in Web IDE for added convenience. -* __Git Provider Integration__: GitHub, GitLab, Bitbucket, Bitbucket Server, Gitea, Gitness, Azure DevOps, AWS CodeCommit, Gogs & Gitee can be connected, allowing easy repo branch or PR pull and commit back from the workspaces. -* __Multiple Project Workspace__: Support for multiple project repositories in the same workspace, making it easy to develop using a micro-service architecture. -* __Reverse Proxy Integration__: Enable collaboration and streamline feedback loops by leveraging reverse proxy functionality. Access preview ports and the Web IDE seamlessly, even behind firewalls. -* __Extensibility__: Enable extensibility with plugin or provider development. Moreover, in any dynamic language, not just Go(Contributions welcome here!). -* __Security__: Automatically creates a VPN connection between the client machine and the development environment, ensuring a fully secure connection. -* __All Ports__: The VPN connection enables access to all ports on the development environments, removing the need to setup port forwards over SSH connection. -* __Works on my Machine__: Never experience it again. -## Quick Start ### Mac / Linux + ```bash -curl -sfL https://download.daytona.io/daytona/install.sh | sudo bash && daytona server -y && daytona +curl -sfL get.daytona.io | sudo bash && daytona server -y && daytona ``` + ### Windows -
-Windows PowerShell -This command downloads and installs Daytona and runs the Daytona Server: ```pwsh -$architecture = if ($env:PROCESSOR_ARCHITECTURE -eq "AMD64") { "amd64" } else { "arm64" } -md -Force "$Env:APPDATA\bin\daytona"; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]'Tls,Tls11,Tls12'; -Invoke-WebRequest -URI "https://download.daytona.io/daytona/latest/daytona-windows-$architecture.exe" -OutFile "$Env:APPDATA\bin\daytona\daytona.exe"; -$env:Path += ";" + $Env:APPDATA + "\bin\daytona"; [Environment]::SetEnvironmentVariable("Path", $env:Path, [System.EnvironmentVariableTarget]::User); -daytona serve; +powershell -Command "irm https://get.daytona.io/windows | iex; daytona serve" ``` -
- ### Create your first dev environment by opening a new terminal, and running: ```bash @@ -90,319 +63,96 @@ daytona create **Start coding.** ----- - -
- -## Why Daytona? -Daytona is a radically simple open source development environment manager. - -Setting up development environments has become increasingly challenging over time, especially when aiming to set up remotely, where the complexity increases by an order of magnitude. The process is so complex that we've compiled a [comprehensive guide](https://www.daytona.io/dotfiles/diy-guide-to-transform-any-machine-into-a-codespace) detailing all the necessary steps to set one up—spanning __5,000 words__, __7 steps__, and requiring anywhere from 15 to __45 minutes__. - -This complexity is unnecessary. - -With Daytona, you need only to execute a single command: `daytona create`. - -Daytona automates the entire process; provisioning the instance, interpreting and applying the configuration, setting up prebuilds, establishing a secure VPN connection, securely connecting your local or a Web IDE, and assigning a fully qualified domain name to the development environment for easy sharing and collaboration. - -As a developer, you can immediately start focusing on what matters most—your code. - - - -## Backstory -We spent most of our careers building cloud development environments. In 2009, we launched what was likely the first commercial [Cloud IDE](https://codeanywhere.com) project. At that time, technology was lacking, forcing us to develop everything from scratch—the IDE, the environment orchestrator, and almost everything else. A lot of people were interested, and over 2.5 million developers signed up! But we were too early, and we asked too much from our users to change how they worked. - -Now, 15 years since its inception, we have noticed quite a few things. First, the technology we wished for back then exists now. Second, approximately 50% of developers work in remote dev environments, and third, and most importantly, setting up development environments has become more complex than ever, both locally and to a greater magnitude for remote. - -So, we took everything we learned and decided to solve these issues once and for all as a fully open-source project. Our goal was to create a single binary that allows you to set up a development environment anywhere you wish, completely free, and finally fulfill the promise that many have attempted to make. - +--- +## Features +- **Quick Setup**: Activate a fully configured development environment with a single command - `daytona create`. +- **Runs everywhere**: Spin up your development environment on any machine; local, remote, cloud-based, physical server or a VM & on any architecture; x86 or ARM. +- **Various Providers Support**: Choose popular providers like AWS, GCP, Azure, DigitalOcean & [more](https://github.com/orgs/daytonaio/repositories?q=daytona-provider) or use Docker on bare metal. +- **IDE Support** : Seamlessly supports [VS Code](https://github.com/microsoft/vscode), [JetBrains](https://www.jetbrains.com/remote-development/gateway/) products and more, ready to use without configuration. Also includes a built-in Web IDE for convenience. +- **Git Provider Integration**: GitHub, GitLab, Bitbucket and [other](https://www.daytona.io/docs/configuration/git-providers/#add-a-git-provider) Git providers can be connected allowing you to start working on a specific branch or PR and to push changes immediately. +- **Configuration File Support**: Support for [dev container](https://containers.dev/) and an upcoming expansion to DevFile, Nix & Flox. +- **Prebuilds System**: Drastically improve environment build times by prebuilding them based on Git Providers' hook events. +- **Reverse Proxy Integration**: Enable collaboration and streamline feedback loops by leveraging our reverse proxy. Access preview ports and the Web IDE seamlessly, even behind firewalls. +- **Security**: Automatically creates a VPN connection between the client machine and the development environment, ensuring a fully secure connection. +- **Works on my Machine**: Never experience it again. +*For a complete feature set including Authentication, Authorization, Observability, Resource Management and IDP, check out our [enterprise offering](https://daytona.zapier.app/). +--- ## Getting Started + ### Requirements -Before starting the installation script, please go over all the necessary requirements: -- __Hardware Resources__: Depending on the project requirements, ensure your machine has sufficient resources. Minimum hardware specification is 1cpu, 2GB of RAM and 10GB of disk space. -- __Docker__: Ensure [Docker](https://www.docker.com/products/docker-desktop/) is installed and running. +Before starting the installation script, if developing locally, ensure [Docker](https://www.docker.com/products/docker-desktop/) is installed and running. +### Initializing Daytona -### Installing Daytona -Daytona allows you to manage your Development Environments using the Daytona CLI. To install it, please execute the following command: +To initialize Daytona, follow these steps: -```bash -# Install Daytona into /usr/local/bin -curl -sf -L https://download.daytona.io/daytona/install.sh | sudo bash +**1. Start the Daytona Server:** +Use this command to initiate the Daytona Server in daemon mode or use `daytona serve` to run it in the foreground: -# OR if you want to install Daytona to some other path where you don`t need sudo -# curl -sf -L https://download.daytona.io/daytona/install.sh | DAYTONA_PATH=/home/user/bin bash +```bash +daytona server ``` -
- Manual installation - If you don't want to use the provided script, download the binary directly from the URL for your specific OS: - - ```bash - curl -sf -L https://download.daytona.io/daytona/latest/daytona-darwin-amd64 -o daytona - curl -sf -L https://download.daytona.io/daytona/latest/daytona-darwin-arm64 -o daytona - curl -sf -L https://download.daytona.io/daytona/latest/daytona-linux-amd64 -o daytona - curl -sf -L https://download.daytona.io/daytona/latest/daytona-linux-arm64 -o daytona - curl -sf -L https://download.daytona.io/daytona/latest/daytona-windows-amd64.exe -o daytona - curl -sf -L https://download.daytona.io/daytona/latest/daytona-windows-arm64.exe -o daytona - ``` - Make sure that path where `daytona` binary is downloaded is in your system PATH. -
- +**2. Register Your Git Provider of Choice:** +Daytona supports GitHub, GitLab, Bitbucket and [more](https://www.daytona.io/docs/configuration/git-providers/#add-a-git-provider) Git Providers. Use this command to set them up: -### Initializing Daytona -To initialize Daytona, follow these steps: - -__1. Start the Daytona Server:__ -This initiates the Daytona Server in daemon mode. Use the command: ```bash -daytona server +daytona git-provider create ``` -__2. Add Your Git Provider of Choice:__ -Daytona supports GitHub, GitLab, Bitbucket, Bitbucket Server, Gitea, Gitness, AWS CodeCommit, Azure DevOps and Gogs. To add them to your profile, use the command: -```bash -daytona git-providers add -``` -Follow the steps provided. +**3. Create Your First Target:** (optional) +By default, Daytona uses the Docker provider to spin up environments on your local machine. For remote development environment setups, use the following command: -__3. Add Your Provider Target:__ -This step is for choosing where to deploy Development Environments. By default, Daytona includes a Docker provider to spin up environments on your local machine. For remote development environments, use the command: -```bash -daytona target set +```bash" +daytona target create ``` -Following the steps this command adds SSH machines to your targets. -__4. Choose Your Default IDE:__ -The default setting for Daytona is VS Code locally. If you prefer, you can switch to VS Code - Browser or any IDE from the JetBrains portfolio using the command: +**4. Choose Your IDE:** +The default IDE for Daytona is the local VS Code installation. To switch to the Web IDE or any other IDE, use: + ```bash daytona ide ``` -Now that you have installed and initialized Daytona, you can proceed to setting up your development environments and start coding instantly. +Now that you have installed and initialized Daytona, you may proceed to setting up your development environments and starting to code instantly. +**4. Create Your First Daytona Development Environment:** +Creating development environments with Daytona is a straightforward process accomplished with just one command which prompts you for two things: +1. Choose the target/provider to decide where to create the dev environment. +2. Select or type in the Git repository you wish to start off with. -### Creating Dev Environments -Creating development environments with Daytona is a straightforward process, accomplished with just one command: -```bash -daytona create -``` - -You can add the `--no-ide` flag if you don't wish to open the IDE immediately after creating the environment. +After making your selections, press enter, and Daytona will handle the rest. -Upon executing this command, you will be prompted with two questions: -1. Choose the provider to decide where to create a dev environment. -2. Select or type the Git repository you wish to use to create a dev environment. - -After making your selections, press enter, and Daytona will handle the rest. All that remains for you to do is to execute the following command to open your default IDE: ```bash -daytona code +daytona create ``` -This command opens your development environment in your preferred IDE, allowing you to start coding instantly. +*You can add the `--no-ide` flag to skip opening the IDE and then use `daytona code` once you're ready to start coding. More info [here](https://www.daytona.io/docs/about/getting-started/). -### Stopping the Daytona Server: -```bash -daytona server stop -``` +**5. Manage the Daytona Server daemon:** -### Restarting the Daytona Server: ```bash -daytona server restart +daytona server [start|stop|restart] ``` -## How to Extend Daytona +--- -Daytona offers flexibility for extension through the creation of plugins and providers. +## Extend Daytona Through Providers - -### Providers -Daytona is designed to be infrastructure-agnostic, capable of creating and managing development environments across various platforms. Providers are the components that encapsulate the logic for provisioning compute resources on a specific target platform. They allow for the configuration of different targets within a single provider, enabling, for instance, multiple AWS profiles within an AWS provider. +Daytona is designed to be infrastructure-agnostic, capable of creating and managing development environments across various platforms. Providers are the components that encapsulate the logic for provisioning compute resources on a specific platform. They allow for the configuration of different target configurations thus enabling, for instance, multiple AWS profiles within an AWS provider. How does it work? When executing the `daytona create` command, Daytona communicates the environment details to the selected provider, which then provisions the necessary compute resources. Once provisioned, Daytona sets up the environment on these resources, allowing the user to interact with the environment seamlessly. -Providers are independent projects that adhere to the Daytona Provider interface. They can be developed in nearly any major programming language. More details coming soon. - - -### Plugins -Plugins enhance Daytona's core functionalities by adding new CLI commands, API methods, or services within the development environments. They offer configurable settings to tailor the plugin's behavior to the user's needs. - -Similar to providers, plugins are independent projects that conform to the Daytona Plugin interface and can be developed in a wide range of programming languages. More details coming soon. - - - - -## Contributing To Daytona - -We welcome contributions to Daytona! Whether you're fixing bugs, improving documentation, suggesting new features, or reporting issues, your help is greatly appreciated. - -### Open Source Licensing - -Daytona is Open Source under the [Apache License 2.0](LICENSE), and is the [copyright of its contributors](NOTICE). - -If you would like to contribute to the software, you must: - - 1. **Read the Developer Certificate of Origin Version 1.1** - - Please review the [Developer Certificate of Origin Version 1.1](https://developercertificate.org/) to understand the contribution requirements. - - 2. **Sign all commits to the Daytona project** - - Ensure that all your commits are signed to comply with the Daytona project's contribution policies. - - This ensures that users, distributors, and other contributors can rely on all the software related to Daytona being contributed under the terms of the [Apache License 2.0](LICENSE). No contributions will be accepted without following this process. - -### Ways to Contribute - -### 1. Reporting Issues and Suggesting Features - -Creating issues is a valuable way to contribute by reporting bugs, suggesting features, or improving documentation. - -Before creating a new issue, search the existing issues [here](https://github.com/daytonaio/daytona/issues) to see if your concern has already been addressed. - -* If no existing issue matches your contribution, follow these steps: - 1. **Identify the Type of Issue** - * **Bug Report:** If you encounter unexpected behavior or errors. - * **Feature Request:** If you have an idea for a new feature or improvement. - * **Documentation Improvement:** If you notice gaps or areas for improvement in the documentation. - 1. **Create a new issue** - * Navigate to Issues: Go to the Issues tab [here](https://github.com/daytonaio/daytona/issues). - * Click on "New Issue": Choose the appropriate template (Bug Report, Feature Request, etc.) if available. - * Fill Out the Issue Template: Provide a clear and concise description of the issue, including steps to reproduce (for bugs) or detailed feature descriptions. - * Submit the Issue: Click "Submit new issue" to create the issue. - 1. **Engage with the Community** - * **Respond to Feedback:** Be prepared to provide additional information or clarification if maintainers or other contributors have questions. - * **Collaborate on Solutions:** If you have ideas for resolving the issue, share them in the comments. - -### 2. Contributing Code - -If you're interested in contributing code to Daytona, follow these steps: - -1. **Fork the Daytona repository** - - [Fork](https://github.com/daytonaio/daytona/fork) the GitHub repository to create your own copy of the repository. - -1. **Add a GitHub provider (if not already registered)** - Before creating your workspace, ensure that you have a GitHub provider registered. If not, run: - ```bash - daytona git-provider add - ``` - -1. **Create a Workspace with Daytona** - - Use the Daytona CLI to create a workspace for your forked repository. Replace YOUR-FORK-URL with the URL of your forked repository. - ```bash - daytona create YOUR-FORK-URL - ``` -1. **Create a new branch** - - Once in the development container, create a new branch for your changes: - ```bash - git checkout -b my-new-feature - ``` - -1. **Running Daytona in development mode** - A `dtn` alias is automatically created inside the Workspace. You can use it to compile and run daytona. - For example: - ```bash - dtn serve - ``` - -1. **Make changes to the project** - - Prepare your changes and ensure your commits are descriptive. The document contains an optional commit template, if desired. - -1. **Test your changes** - - Ensure to test your changes by running the project locally. - Run the following command in the daytona root directory to run the tests: - - ```bash - go test ./... - ``` - -1. **Generate docs** - - Ensure to generate new docs after making command related changes, by running ./hack/generate-cli-docs.sh in the daytona root directory. - - ```bash - ./hack/generate-cli-docs.sh - ``` - -1. **Generate new API client** - - Ensure to generate a new API client after making changes related to the API spec. - Run the following command in the daytona root directory: - - ```bash - ./hack/swagger.sh - ``` - -1. **Check for lint errors** - - Ensure that you have no lint errors. We use golangci-lint as our linter which is automatically installed. - Run the following command in the daytona root directory to check for linting errors: - - ```bash - golangci-lint run - ``` - -1. **Sign off on your commits** - - Ensure that you sign off on all your commits to comply with the DCO v1.1. We have more details in [Prepare your changes](https://github.com/daytonaio/daytona/blob/main/PREPARING_YOUR_CHANGES.md). - - To sign off on your Git commits more easily, you can use the -s or --signoff option when making a commit. This adds a "Signed-off-by" line to your commit message automatically, which is required to comply with the DCO v1.1. - - Here's how you can do it: - - ```bash - git commit -s -m "Your commit message" - ``` - This command adds the necessary sign-off to your commit without needing to rebase later. - - If you've already made commits without the sign-off, you can add it retrospectively by rebasing: - - ```bash - git rebase HEAD~1 --signoff - git push --force-with-lease origin my-new-feature - ``` - -1. **Push your changes and create a pull request** - - Push your changes to your forked repository and create a pull request from your branch in your forked repository to the main Daytona repository. - If you're new to GitHub, read about [pull requests](https://help.github.com/articles/about-pull-requests/). You are welcome to submit your pull request for commentary or review before it is complete by creating a [draft pull request](https://help.github.com/en/articles/about-pull-requests#draft-pull-requests). Please include specific questions or items you'd like feedback on. - -1. **Wait for review** - - A Daytona team member will take a look at your PR and either merge, comment, and/or assign someone for review. - -## License - -This repository contains Daytona, covered under the [Apache License 2.0](LICENSE), except where noted (any Daytona logos or trademarks are not covered under the Apache License, and should be explicitly noted by a LICENSE file.) - -Daytona is a product produced from this open source software, exclusively by Daytona Platforms, Inc. It is distributed under our commercial terms. - -Others are allowed to make their own distribution of the software, but they cannot use any of the Daytona trademarks, cloud services, etc. - -We explicitly grant permission for you to make a build that includes our trademarks while developing Daytona itself. You may not publish or share the build, and you may not use that build to run Daytona for any other purpose. - -You can read more in our [packinging guidelines](PACKAGING.md). - -## Code of Conduct - - -This project has adapted the Code of Conduct from the [Contributor Covenant](https://www.contributor-covenant.org/). For more information see the [Code of Conduct](CODE_OF_CONDUCT.md) or contact [codeofconduct@daytona.io.](mailto:codeofconduct@daytona.io) with any additional questions or comments. - -## Questions +Providers are independent projects that adhere to the Daytona Provider interface. View all currently supported providers [here](https://github.com/orgs/daytonaio/repositories?q=daytona-provider). +## Contributing -For more information on how to use and develop Daytona, talk to us on -[Slack](https://go.daytona.io/slack). +Daytona is Open Source under the [Apache License 2.0](LICENSE), and is the [copyright of its contributors](NOTICE). If you would like to contribute to the software, read the Developer Certificate of Origin Version 1.1 (https://developercertificate.org/). Afterwards, navigate to the [contributing guide](CONTRIBUTING.md) to get started. \ No newline at end of file diff --git a/assets/images/create-profile.png b/assets/images/create-profile.png deleted file mode 100644 index c5370a5a31..0000000000 Binary files a/assets/images/create-profile.png and /dev/null differ diff --git a/assets/images/create-workspace.png b/assets/images/create-workspace.png deleted file mode 100644 index 0a13d36350..0000000000 Binary files a/assets/images/create-workspace.png and /dev/null differ diff --git a/assets/images/daytona-core.png b/assets/images/daytona-core.png deleted file mode 100644 index 398096bd9a..0000000000 Binary files a/assets/images/daytona-core.png and /dev/null differ diff --git a/assets/images/daytona_demo.gif b/assets/images/daytona_demo.gif index beba88ac06..0a18b2e8b1 100644 Binary files a/assets/images/daytona_demo.gif and b/assets/images/daytona_demo.gif differ diff --git a/assets/images/list-workspace.png b/assets/images/list-workspace.png deleted file mode 100644 index e43028d1e8..0000000000 Binary files a/assets/images/list-workspace.png and /dev/null differ diff --git a/assets/images/ph-readme.png b/assets/images/ph-readme.png deleted file mode 100644 index 9c38620ce6..0000000000 Binary files a/assets/images/ph-readme.png and /dev/null differ diff --git a/assets/images/ssh-workspace.png b/assets/images/ssh-workspace.png deleted file mode 100644 index a8318dba4a..0000000000 Binary files a/assets/images/ssh-workspace.png and /dev/null differ diff --git a/cmd/daytona/config/config.go b/cmd/daytona/config/config.go index 9989751578..2e555ac8bd 100644 --- a/cmd/daytona/config/config.go +++ b/cmd/daytona/config/config.go @@ -89,7 +89,7 @@ func GetConfig() (*Config, error) { return &c, nil } -var ErrNoProfilesFound = errors.New("no profiles found. Run `daytona serve` to create a default profile or `daytona profile add` to connect to a remote server") +var ErrNoProfilesFound = errors.New("no profiles found. Run `daytona serve` to create a default profile or `daytona profile create` to connect to a remote server") func (c *Config) GetActiveProfile() (Profile, error) { if len(c.Profiles) == 0 { @@ -215,12 +215,7 @@ func DeleteConfigDir() error { return err } - err = os.RemoveAll(configDir) - if err != nil { - return err - } - - return nil + return os.RemoveAll(configDir) } func TelemetryEnabled() bool { diff --git a/cmd/daytona/config/ssh_file.go b/cmd/daytona/config/ssh_file.go index b147bd07cf..00daa44ada 100644 --- a/cmd/daytona/config/ssh_file.go +++ b/cmd/daytona/config/ssh_file.go @@ -114,21 +114,21 @@ func UnlinkSshFiles() error { // Add ssh entry -func generateSshConfigEntry(profileId, workspaceId, projectName, knownHostsPath string, gpgForward bool) (string, error) { +func generateSshConfigEntry(profileId, resourceId, knownHostsPath string, gpgForward bool) (string, error) { daytonaPath, err := os.Executable() if err != nil { return "", err } tab := "\t" - projectHostname := GetProjectHostname(profileId, workspaceId, projectName) + resourceHostname := GetHostname(profileId, resourceId) config := fmt.Sprintf("Host %s\n"+ tab+"User daytona\n"+ tab+"StrictHostKeyChecking no\n"+ tab+"UserKnownHostsFile %s\n"+ - tab+"ProxyCommand \"%s\" ssh-proxy %s %s %s\n"+ - tab+"ForwardAgent yes\n", projectHostname, knownHostsPath, daytonaPath, profileId, workspaceId, projectName) + tab+"ProxyCommand \"%s\" ssh-proxy %s %s\n"+ + tab+"ForwardAgent yes\n", resourceHostname, knownHostsPath, daytonaPath, profileId, resourceId) if gpgForward { localSocket, err := getLocalGPGSocket() @@ -137,7 +137,7 @@ func generateSshConfigEntry(profileId, workspaceId, projectName, knownHostsPath return config, nil } - remoteSocket, err := getRemoteGPGSocket(projectHostname) + remoteSocket, err := getRemoteGPGSocket(resourceHostname) if err != nil { log.Trace(err) return config, nil @@ -153,7 +153,7 @@ func generateSshConfigEntry(profileId, workspaceId, projectName, knownHostsPath return config, nil } -func EnsureSshConfigEntryAdded(profileId, workspaceName, projectName string, gpgKey string) error { +func EnsureSshConfigEntryAdded(profileId, resourceId string, gpgKey *string) error { err := ensureSshFilesLinked() if err != nil { return err @@ -164,16 +164,17 @@ func EnsureSshConfigEntryAdded(profileId, workspaceName, projectName string, gpg knownHostsFile := getKnownHostsFile() + // Read existing content from the file existingContent, err := ReadSshConfig(configPath) - if err != nil { + if err != nil && !os.IsNotExist(err) { return err } var configGenerated bool - regexWithoutGPG := regexp.MustCompile(fmt.Sprintf(`(?m)^Host %s-%s-%s\s*\n(?:\s+[^\n]*\n?)*`, profileId, workspaceName, projectName)) - regexWithGPG := regexp.MustCompile(fmt.Sprintf(`(?m)^Host %s-%s-%s\s*\n(?:\s+[^\n]*\n?)*StreamLocalBindUnlink\s+yes\s*\n(?:\s+[^\n]*\n?)*RemoteForward\s+[^\s]+\s+[^\s]+\s*\n`, profileId, workspaceName, projectName)) + regexWithoutGPG := regexp.MustCompile(fmt.Sprintf(`(?m)^Host %s-%s\s*\n(?:\s+[^\n]*\n?)*`, profileId, resourceId)) + regexWithGPG := regexp.MustCompile(fmt.Sprintf(`(?m)^Host %s-%s\s*\n(?:\s+[^\n]*\n?)*StreamLocalBindUnlink\s+yes\s*\n(?:\s+[^\n]*\n?)*RemoteForward\s+[^\s]+\s+[^\s]+\s*\n`, profileId, resourceId)) if !regexWithoutGPG.MatchString(existingContent) { - newContent, err := appendSshConfigEntry(configPath, profileId, workspaceName, projectName, knownHostsFile, false, existingContent) + newContent, err := appendSshConfigEntry(configPath, profileId, resourceId, knownHostsFile, false, existingContent) if err != nil { return err } @@ -181,14 +182,14 @@ func EnsureSshConfigEntryAdded(profileId, workspaceName, projectName string, gpg configGenerated = true } - if gpgKey != "" && !regexWithGPG.MatchString(existingContent) { - _, err := appendSshConfigEntry(configPath, profileId, workspaceName, projectName, knownHostsFile, true, existingContent) + if gpgKey != nil && *gpgKey != "" && !regexWithGPG.MatchString(existingContent) { + _, err := appendSshConfigEntry(configPath, profileId, resourceId, knownHostsFile, true, existingContent) if err != nil { return err } - projectHostname := GetProjectHostname(profileId, workspaceName, projectName) - err = ExportGPGKey(gpgKey, projectHostname) + hostname := GetHostname(profileId, resourceId) + err = ExportGPGKey(*gpgKey, hostname) if err != nil { return err } @@ -197,11 +198,11 @@ func EnsureSshConfigEntryAdded(profileId, workspaceName, projectName string, gpg } if !configGenerated { - updatedContent, err := regenerateProxyCommand(existingContent, profileId, workspaceName, projectName) + updatedContent, err := regenerateProxyCommand(existingContent, profileId, resourceId) if err != nil { return err } - err = UpdateWorkspaceSshEntry(profileId, workspaceName, projectName, updatedContent) + err = UpdateSshEntry(profileId, resourceId, updatedContent) if err != nil { return err } @@ -210,21 +211,21 @@ func EnsureSshConfigEntryAdded(profileId, workspaceName, projectName string, gpg return nil } -func regenerateProxyCommand(existingContent, profileId, workspaceId, projectName string) (string, error) { +func regenerateProxyCommand(existingContent, profileId, resourceId string) (string, error) { daytonaPath, err := os.Executable() if err != nil { return "", err } - hostLine := fmt.Sprintf("Host %s", GetProjectHostname(profileId, workspaceId, projectName)) + hostLine := fmt.Sprintf("Host %s", GetHostname(profileId, resourceId)) regex := regexp.MustCompile(fmt.Sprintf(`%s\s*\n(?:\t.*\n?)*`, hostLine)) matchedEntry := regex.FindString(existingContent) if matchedEntry == "" { - return "", fmt.Errorf("no SSH entry found for project %s", projectName) + return "", fmt.Errorf("no SSH entry found for resource %s", resourceId) } re := regexp.MustCompile(`(?m)^\s*ProxyCommand\s+.*$`) - updatedContent := re.ReplaceAllString(matchedEntry, fmt.Sprintf("\tProxyCommand \"%s\" ssh-proxy %s %s %s", daytonaPath, profileId, workspaceId, projectName)) + updatedContent := re.ReplaceAllString(matchedEntry, fmt.Sprintf("\tProxyCommand \"%s\" ssh-proxy %s %s", daytonaPath, profileId, resourceId)) return updatedContent, nil } @@ -236,8 +237,8 @@ func getKnownHostsFile() string { return "/dev/null" } -func appendSshConfigEntry(configPath, profileId, workspaceId, projectName, knownHostsFile string, gpgForward bool, existingContent string) (string, error) { - data, err := generateSshConfigEntry(profileId, workspaceId, projectName, knownHostsFile, gpgForward) +func appendSshConfigEntry(configPath, profileId, resourceId, knownHostsFile string, gpgForward bool, existingContent string) (string, error) { + data, err := generateSshConfigEntry(profileId, resourceId, knownHostsFile, gpgForward) if err != nil { return "", err } @@ -248,7 +249,7 @@ func appendSshConfigEntry(configPath, profileId, workspaceId, projectName, known } // We want to remove the config entry gpg counterpart - configCounterpart, err := generateSshConfigEntry(profileId, workspaceId, projectName, knownHostsFile, !gpgForward) + configCounterpart, err := generateSshConfigEntry(profileId, resourceId, knownHostsFile, !gpgForward) if err != nil { return "", err } @@ -281,8 +282,8 @@ func getLocalGPGSocket() (string, error) { return strings.TrimSpace(string(output)), nil } -func getRemoteGPGSocket(projectHostname string) (string, error) { - cmd := exec.Command("ssh", projectHostname, "gpgconf --list-dir agent-socket") +func getRemoteGPGSocket(resourceHostname string) (string, error) { + cmd := exec.Command("ssh", resourceHostname, "gpgconf --list-dir agent-socket") output, err := cmd.Output() if err != nil { return "", fmt.Errorf("failed to get remote GPG socket: %v", err) @@ -290,7 +291,7 @@ func getRemoteGPGSocket(projectHostname string) (string, error) { return strings.TrimSpace(string(output)), nil } -func ExportGPGKey(keyID, projectHostname string) error { +func ExportGPGKey(keyID, resourceHostname string) error { exportCmd := exec.Command("gpg", "--export", keyID) var output bytes.Buffer exportCmd.Stdout = &output @@ -299,7 +300,7 @@ func ExportGPGKey(keyID, projectHostname string) error { return err } - importCmd := exec.Command("ssh", projectHostname, "gpg --import") + importCmd := exec.Command("ssh", resourceHostname, "gpg --import") importCmd.Stdin = &output return importCmd.Run() @@ -327,7 +328,8 @@ func writeSshConfig(configPath, newContent string) error { return nil } -func RemoveWorkspaceSshEntries(profileId, workspaceId, projectName string) error { +// RemoveSshEntries removes all SSH entries for a given profileId and resourceId +func RemoveSshEntries(profileId, resourceId string) error { sshDir := filepath.Join(SshHomeDir, ".ssh") configPath := filepath.Join(sshDir, "daytona_config") @@ -337,8 +339,9 @@ func RemoveWorkspaceSshEntries(profileId, workspaceId, projectName string) error return err } - hostLine := fmt.Sprintf("Host %s", GetProjectHostname(profileId, workspaceId, projectName)) - regex := regexp.MustCompile(fmt.Sprintf(`%s\s*\n(?:\t.*\n?)*`, hostLine)) + // Define the regex pattern to match Host entries for the given profileId and resourceId + regex := regexp.MustCompile(fmt.Sprintf(`Host %s-%s\n(?:\t.*\n?)*`, profileId, resourceId)) + contentToDelete := regex.FindString(existingContent) if contentToDelete == "" { return nil @@ -348,15 +351,10 @@ func RemoveWorkspaceSshEntries(profileId, workspaceId, projectName string) error newContent = strings.TrimSpace(newContent) // Write the updated content back to the config file - err = writeSshConfig(configPath, newContent) - if err != nil { - return err - } - - return nil + return writeSshConfig(configPath, newContent) } -func UpdateWorkspaceSshEntry(profileId, workspaceId, projectName, updatedContent string) error { +func UpdateSshEntry(profileId, resourceId, updatedContent string) error { sshDir := filepath.Join(SshHomeDir, ".ssh") configPath := filepath.Join(sshDir, "daytona_config") @@ -365,11 +363,11 @@ func UpdateWorkspaceSshEntry(profileId, workspaceId, projectName, updatedContent return err } - hostLine := fmt.Sprintf("Host %s", GetProjectHostname(profileId, workspaceId, projectName)) + hostLine := fmt.Sprintf("Host %s", GetHostname(profileId, resourceId)) regex := regexp.MustCompile(fmt.Sprintf(`%s\s*\n(?:\t.*\n?)*`, hostLine)) oldContent := regex.FindString(existingContent) if oldContent == "" { - return fmt.Errorf("no SSH entry found for project %s", projectName) + return fmt.Errorf("no SSH entry found for resource %s", resourceId) } existingContent = strings.ReplaceAll(existingContent, oldContent, updatedContent) @@ -381,8 +379,8 @@ func UpdateWorkspaceSshEntry(profileId, workspaceId, projectName, updatedContent return nil } -func GetProjectHostname(profileId, workspaceId, projectName string) string { - return fmt.Sprintf("%s-%s-%s", profileId, workspaceId, projectName) +func GetHostname(profileId, resourceId string) string { + return fmt.Sprintf("%s-%s", profileId, resourceId) } func init() { diff --git a/cmd/daytona/main.go b/cmd/daytona/main.go index 9830581c07..c42be7a680 100644 --- a/cmd/daytona/main.go +++ b/cmd/daytona/main.go @@ -9,18 +9,18 @@ import ( golog "log" - "github.com/daytonaio/daytona/internal" "github.com/daytonaio/daytona/internal/util" "github.com/daytonaio/daytona/pkg/cmd" - "github.com/daytonaio/daytona/pkg/cmd/workspacemode" + "github.com/daytonaio/daytona/pkg/cmd/agentmode" + "github.com/daytonaio/daytona/pkg/common" "github.com/rs/zerolog" zlog "github.com/rs/zerolog/log" log "github.com/sirupsen/logrus" ) func main() { - if internal.WorkspaceMode() { - err := workspacemode.Execute() + if common.AgentMode() { + err := agentmode.Execute() if err != nil { log.Fatal(err) } diff --git a/docs/workspace_mode/daytona.md b/docs/agent_mode/daytona.md similarity index 65% rename from docs/workspace_mode/daytona.md rename to docs/agent_mode/daytona.md index 2719fb1581..820f97fc28 100644 --- a/docs/workspace_mode/daytona.md +++ b/docs/agent_mode/daytona.md @@ -1,10 +1,10 @@ ## daytona -Use the Daytona CLI to manage your workspace +Daytona is a Dev Environment Manager ### Synopsis -Use the Daytona CLI to manage your workspace +Daytona is a Dev Environment Manager ``` daytona [flags] @@ -22,13 +22,10 @@ daytona [flags] * [daytona agent](daytona_agent.md) - Start the agent process * [daytona autocomplete](daytona_autocomplete.md) - Adds a completion script for your shell environment * [daytona docs](daytona_docs.md) - Opens the Daytona documentation in your default browser. -* [daytona expose](daytona_expose.md) - Expose a local port over stdout - Used by the Daytona CLI to make direct connections to the project +* [daytona expose](daytona_expose.md) - Expose a local port over stdout - Used by the Daytona CLI to make direct connections to the workspace * [daytona forward](daytona_forward.md) - Forward a port publicly via an URL -* [daytona info](daytona_info.md) - Show project info +* [daytona info](daytona_info.md) - Show resource info * [daytona list](daytona_list.md) - List workspaces -* [daytona logs](daytona_logs.md) - View logs for a workspace/project -* [daytona restart](daytona_restart.md) - Restart the project -* [daytona start](daytona_start.md) - Start the project -* [daytona stop](daytona_stop.md) - Stop the project +* [daytona logs](daytona_logs.md) - View resource logs * [daytona version](daytona_version.md) - Print the version number diff --git a/docs/workspace_mode/daytona_agent.md b/docs/agent_mode/daytona_agent.md similarity index 70% rename from docs/workspace_mode/daytona_agent.md rename to docs/agent_mode/daytona_agent.md index 0a1f1e81fd..157fc8323e 100644 --- a/docs/workspace_mode/daytona_agent.md +++ b/docs/agent_mode/daytona_agent.md @@ -9,7 +9,7 @@ daytona agent [flags] ### Options ``` - --host Run the agent in host mode + --target Run the agent in target mode ``` ### Options inherited from parent commands @@ -20,6 +20,6 @@ daytona agent [flags] ### SEE ALSO -* [daytona](daytona.md) - Use the Daytona CLI to manage your workspace +* [daytona](daytona.md) - Daytona is a Dev Environment Manager * [daytona agent logs](daytona_agent_logs.md) - Output Daytona Agent logs diff --git a/docs/workspace_mode/daytona_agent_logs.md b/docs/agent_mode/daytona_agent_logs.md similarity index 100% rename from docs/workspace_mode/daytona_agent_logs.md rename to docs/agent_mode/daytona_agent_logs.md diff --git a/docs/workspace_mode/daytona_autocomplete.md b/docs/agent_mode/daytona_autocomplete.md similarity index 77% rename from docs/workspace_mode/daytona_autocomplete.md rename to docs/agent_mode/daytona_autocomplete.md index 4689ddb46a..2a2d749125 100644 --- a/docs/workspace_mode/daytona_autocomplete.md +++ b/docs/agent_mode/daytona_autocomplete.md @@ -14,5 +14,5 @@ daytona autocomplete [bash|zsh|fish|powershell] [flags] ### SEE ALSO -* [daytona](daytona.md) - Use the Daytona CLI to manage your workspace +* [daytona](daytona.md) - Daytona is a Dev Environment Manager diff --git a/docs/workspace_mode/daytona_docs.md b/docs/agent_mode/daytona_docs.md similarity index 74% rename from docs/workspace_mode/daytona_docs.md rename to docs/agent_mode/daytona_docs.md index 62f73691da..612505ce71 100644 --- a/docs/workspace_mode/daytona_docs.md +++ b/docs/agent_mode/daytona_docs.md @@ -14,5 +14,5 @@ daytona docs [flags] ### SEE ALSO -* [daytona](daytona.md) - Use the Daytona CLI to manage your workspace +* [daytona](daytona.md) - Daytona is a Dev Environment Manager diff --git a/docs/workspace_mode/daytona_expose.md b/docs/agent_mode/daytona_expose.md similarity index 67% rename from docs/workspace_mode/daytona_expose.md rename to docs/agent_mode/daytona_expose.md index 16a3b1dc89..10710ddb16 100644 --- a/docs/workspace_mode/daytona_expose.md +++ b/docs/agent_mode/daytona_expose.md @@ -1,6 +1,6 @@ ## daytona expose -Expose a local port over stdout - Used by the Daytona CLI to make direct connections to the project +Expose a local port over stdout - Used by the Daytona CLI to make direct connections to the workspace ``` daytona expose [PORT] [flags] @@ -14,5 +14,5 @@ daytona expose [PORT] [flags] ### SEE ALSO -* [daytona](daytona.md) - Use the Daytona CLI to manage your workspace +* [daytona](daytona.md) - Daytona is a Dev Environment Manager diff --git a/docs/workspace_mode/daytona_forward.md b/docs/agent_mode/daytona_forward.md similarity index 73% rename from docs/workspace_mode/daytona_forward.md rename to docs/agent_mode/daytona_forward.md index 484087da37..926b4ae0d3 100644 --- a/docs/workspace_mode/daytona_forward.md +++ b/docs/agent_mode/daytona_forward.md @@ -14,5 +14,5 @@ daytona forward [PORT] [flags] ### SEE ALSO -* [daytona](daytona.md) - Use the Daytona CLI to manage your workspace +* [daytona](daytona.md) - Daytona is a Dev Environment Manager diff --git a/docs/workspace_mode/daytona_info.md b/docs/agent_mode/daytona_info.md similarity index 72% rename from docs/workspace_mode/daytona_info.md rename to docs/agent_mode/daytona_info.md index 4fc31aece4..84fa076ba7 100644 --- a/docs/workspace_mode/daytona_info.md +++ b/docs/agent_mode/daytona_info.md @@ -1,6 +1,6 @@ ## daytona info -Show project info +Show resource info ``` daytona info [flags] @@ -20,5 +20,5 @@ daytona info [flags] ### SEE ALSO -* [daytona](daytona.md) - Use the Daytona CLI to manage your workspace +* [daytona](daytona.md) - Daytona is a Dev Environment Manager diff --git a/docs/workspace_mode/daytona_list.md b/docs/agent_mode/daytona_list.md similarity index 68% rename from docs/workspace_mode/daytona_list.md rename to docs/agent_mode/daytona_list.md index 44ce1885a0..10e0f9405b 100644 --- a/docs/workspace_mode/daytona_list.md +++ b/docs/agent_mode/daytona_list.md @@ -10,7 +10,7 @@ daytona list [flags] ``` -f, --format string Output format. Must be one of (yaml, json) - -v, --verbose Show verbose output + -l, --label strings Filter by label ``` ### Options inherited from parent commands @@ -21,5 +21,5 @@ daytona list [flags] ### SEE ALSO -* [daytona](daytona.md) - Use the Daytona CLI to manage your workspace +* [daytona](daytona.md) - Daytona is a Dev Environment Manager diff --git a/docs/agent_mode/daytona_logs.md b/docs/agent_mode/daytona_logs.md new file mode 100644 index 0000000000..6f21f58ec6 --- /dev/null +++ b/docs/agent_mode/daytona_logs.md @@ -0,0 +1,18 @@ +## daytona logs + +View resource logs + +``` +daytona logs [flags] +``` + +### Options inherited from parent commands + +``` + --help help for daytona +``` + +### SEE ALSO + +* [daytona](daytona.md) - Daytona is a Dev Environment Manager + diff --git a/docs/workspace_mode/daytona_version.md b/docs/agent_mode/daytona_version.md similarity index 71% rename from docs/workspace_mode/daytona_version.md rename to docs/agent_mode/daytona_version.md index 0e8e0ed22c..2f0f9fb6a6 100644 --- a/docs/workspace_mode/daytona_version.md +++ b/docs/agent_mode/daytona_version.md @@ -14,5 +14,5 @@ daytona version [flags] ### SEE ALSO -* [daytona](daytona.md) - Use the Daytona CLI to manage your workspace +* [daytona](daytona.md) - Daytona is a Dev Environment Manager diff --git a/docs/daytona.md b/docs/daytona.md index c1d845a9d6..2b85864fb7 100644 --- a/docs/daytona.md +++ b/docs/daytona.md @@ -24,30 +24,31 @@ daytona [flags] * [daytona build](daytona_build.md) - Manage builds * [daytona code](daytona_code.md) - Open a workspace in your preferred IDE * [daytona config](daytona_config.md) - Output Daytona configuration -* [daytona container-registry](daytona_container-registry.md) - Manage container registries * [daytona create](daytona_create.md) - Create a workspace * [daytona delete](daytona_delete.md) - Delete a workspace * [daytona docs](daytona_docs.md) - Opens the Daytona documentation in your default browser. -* [daytona env](daytona_env.md) - Manage profile environment variables that are added to all workspaces -* [daytona forward](daytona_forward.md) - Forward a port from a project to your local machine -* [daytona git-providers](daytona_git-providers.md) - Manage Git providers +* [daytona env](daytona_env.md) - Manage server environment variables that are added to all targets and workspaces +* [daytona forward](daytona_forward.md) - Forward a port from a workspace to your local machine +* [daytona git-provider](daytona_git-provider.md) - Manage Git provider configs * [daytona ide](daytona_ide.md) - Choose the default IDE * [daytona info](daytona_info.md) - Show workspace info * [daytona list](daytona_list.md) - List workspaces -* [daytona logs](daytona_logs.md) - View logs for a workspace/project +* [daytona logs](daytona_logs.md) - View the logs of a workspace * [daytona prebuild](daytona_prebuild.md) - Manage prebuilds * [daytona profile](daytona_profile.md) - Manage profiles -* [daytona project-config](daytona_project-config.md) - Manage project configs * [daytona provider](daytona_provider.md) - Manage providers * [daytona purge](daytona_purge.md) - Purges all Daytona data from the current device * [daytona restart](daytona_restart.md) - Restart a workspace +* [daytona runner](daytona_runner.md) - Manage the runner * [daytona serve](daytona_serve.md) - Run the server process in the current terminal session * [daytona server](daytona_server.md) - Start the server process in daemon mode -* [daytona ssh](daytona_ssh.md) - SSH into a project using the terminal +* [daytona ssh](daytona_ssh.md) - SSH into a workspace using the terminal * [daytona start](daytona_start.md) - Start a workspace * [daytona stop](daytona_stop.md) - Stop a workspace -* [daytona target](daytona_target.md) - Manage provider targets +* [daytona target](daytona_target.md) - Manage targets +* [daytona target-config](daytona_target-config.md) - Manage target configs * [daytona telemetry](daytona_telemetry.md) - Manage telemetry collection +* [daytona template](daytona_template.md) - Manage workspace templates * [daytona update](daytona_update.md) - Update Daytona CLI * [daytona use](daytona_use.md) - Use profile [PROFILE_NAME] * [daytona version](daytona_version.md) - Print the version number diff --git a/docs/daytona_api-key.md b/docs/daytona_api-key.md index 11ac2ece14..9d965b3200 100644 --- a/docs/daytona_api-key.md +++ b/docs/daytona_api-key.md @@ -11,7 +11,7 @@ Api Key commands ### SEE ALSO * [daytona](daytona.md) - Daytona is a Dev Environment Manager -* [daytona api-key generate](daytona_api-key_generate.md) - Generate a new API key +* [daytona api-key create](daytona_api-key_create.md) - Create a new API key +* [daytona api-key delete](daytona_api-key_delete.md) - Delete an API key * [daytona api-key list](daytona_api-key_list.md) - List API keys -* [daytona api-key revoke](daytona_api-key_revoke.md) - Revoke an API key diff --git a/docs/daytona_api-key_generate.md b/docs/daytona_api-key_create.md similarity index 65% rename from docs/daytona_api-key_generate.md rename to docs/daytona_api-key_create.md index 66d7b563d4..3d673cab22 100644 --- a/docs/daytona_api-key_generate.md +++ b/docs/daytona_api-key_create.md @@ -1,9 +1,9 @@ -## daytona api-key generate +## daytona api-key create -Generate a new API key +Create a new API key ``` -daytona api-key generate [NAME] [flags] +daytona api-key create [NAME] [flags] ``` ### Options inherited from parent commands diff --git a/docs/daytona_api-key_revoke.md b/docs/daytona_api-key_delete.md similarity index 73% rename from docs/daytona_api-key_revoke.md rename to docs/daytona_api-key_delete.md index 90366c5c1b..b7b63e694d 100644 --- a/docs/daytona_api-key_revoke.md +++ b/docs/daytona_api-key_delete.md @@ -1,9 +1,9 @@ -## daytona api-key revoke +## daytona api-key delete -Revoke an API key +Delete an API key ``` -daytona api-key revoke [NAME] [flags] +daytona api-key delete [NAME] [flags] ``` ### Options diff --git a/docs/daytona_build.md b/docs/daytona_build.md index 25069c66b3..b92a3b7ee7 100644 --- a/docs/daytona_build.md +++ b/docs/daytona_build.md @@ -15,5 +15,5 @@ Manage builds * [daytona build info](daytona_build_info.md) - Show build info * [daytona build list](daytona_build_list.md) - List all builds * [daytona build logs](daytona_build_logs.md) - View logs for build -* [daytona build run](daytona_build_run.md) - Run a build from a project config +* [daytona build run](daytona_build_run.md) - Run a build from a workspace template diff --git a/docs/daytona_build_run.md b/docs/daytona_build_run.md index 61ba79e017..f8067724a2 100644 --- a/docs/daytona_build_run.md +++ b/docs/daytona_build_run.md @@ -1,6 +1,6 @@ ## daytona build run -Run a build from a project config +Run a build from a workspace template ``` daytona build run [flags] diff --git a/docs/daytona_code.md b/docs/daytona_code.md index a37f6d179b..1ccd206fa4 100644 --- a/docs/daytona_code.md +++ b/docs/daytona_code.md @@ -3,7 +3,7 @@ Open a workspace in your preferred IDE ``` -daytona code [WORKSPACE] [PROJECT] [flags] +daytona code [WORKSPACE] [flags] ``` ### Options diff --git a/docs/daytona_container-registry.md b/docs/daytona_container-registry.md deleted file mode 100644 index f101ccfbd7..0000000000 --- a/docs/daytona_container-registry.md +++ /dev/null @@ -1,17 +0,0 @@ -## daytona container-registry - -Manage container registries - -### Options inherited from parent commands - -``` - --help help for daytona -``` - -### SEE ALSO - -* [daytona](daytona.md) - Daytona is a Dev Environment Manager -* [daytona container-registry delete](daytona_container-registry_delete.md) - Delete a container registry -* [daytona container-registry list](daytona_container-registry_list.md) - Lists container registries -* [daytona container-registry set](daytona_container-registry_set.md) - Set container registry - diff --git a/docs/daytona_container-registry_delete.md b/docs/daytona_container-registry_delete.md deleted file mode 100644 index bbf017d9f9..0000000000 --- a/docs/daytona_container-registry_delete.md +++ /dev/null @@ -1,18 +0,0 @@ -## daytona container-registry delete - -Delete a container registry - -``` -daytona container-registry delete [flags] -``` - -### Options inherited from parent commands - -``` - --help help for daytona -``` - -### SEE ALSO - -* [daytona container-registry](daytona_container-registry.md) - Manage container registries - diff --git a/docs/daytona_container-registry_list.md b/docs/daytona_container-registry_list.md deleted file mode 100644 index ca07652b86..0000000000 --- a/docs/daytona_container-registry_list.md +++ /dev/null @@ -1,24 +0,0 @@ -## daytona container-registry list - -Lists container registries - -``` -daytona container-registry list [flags] -``` - -### Options - -``` - -f, --format string Output format. Must be one of (yaml, json) -``` - -### Options inherited from parent commands - -``` - --help help for daytona -``` - -### SEE ALSO - -* [daytona container-registry](daytona_container-registry.md) - Manage container registries - diff --git a/docs/daytona_container-registry_set.md b/docs/daytona_container-registry_set.md deleted file mode 100644 index dd3ed61d0c..0000000000 --- a/docs/daytona_container-registry_set.md +++ /dev/null @@ -1,26 +0,0 @@ -## daytona container-registry set - -Set container registry - -``` -daytona container-registry set [flags] -``` - -### Options - -``` - -p, --password string Password - -s, --server string Server - -u, --username string Username -``` - -### Options inherited from parent commands - -``` - --help help for daytona -``` - -### SEE ALSO - -* [daytona container-registry](daytona_container-registry.md) - Manage container registries - diff --git a/docs/daytona_create.md b/docs/daytona_create.md index 03f852d4df..07597efd7c 100644 --- a/docs/daytona_create.md +++ b/docs/daytona_create.md @@ -3,25 +3,25 @@ Create a workspace ``` -daytona create [REPOSITORY_URL | PROJECT_CONFIG_NAME]... [flags] +daytona create [REPOSITORY_URL | WORKSPACE_CONFIG_NAME]... [flags] ``` ### Options ``` - --blank Create a blank project without using existing configurations - --branch strings Specify the Git branches to use in the projects + --blank Create a blank workspace without using existing templates + --branch strings Specify the Git branches to use in the workspaces --builder BuildChoice Specify the builder (currently auto/devcontainer/none) - --custom-image string Create the project with the custom image passed as the flag value; Requires setting --custom-image-user flag as well - --custom-image-user string Create the project with the custom image user passed as the flag value; Requires setting --custom-image flag as well + --custom-image string Create the workspace with the custom image passed as the flag value; Requires setting --custom-image-user flag as well + --custom-image-user string Create the workspace with the custom image user passed as the flag value; Requires setting --custom-image flag as well --devcontainer-path string Automatically assign the devcontainer builder with the path passed as the flag value --env stringArray Specify environment variables (e.g. --env 'KEY1=VALUE1' --env 'KEY2=VALUE2' ...') --git-provider-config string Specify the Git provider configuration ID or alias -i, --ide string Specify the IDE (vscode, code-insiders, browser, cursor, codium, codium-insiders, ssh, jupyter, fleet, positron, zed, windsurf, clion, goland, intellij, phpstorm, pycharm, rider, rubymine, webstorm) + --label stringArray Specify labels (e.g. --label 'label.key1=VALUE1' --label 'label.key2=VALUE2' ...) --manual Manually enter the Git repository - --multi-project Workspace with multiple projects/repos - --name string Specify the workspace name - -n, --no-ide Do not open the workspace in the IDE after workspace creation + --multi-workspace Target with multiple workspaces/repos + -n, --no-ide Do not open the target in the IDE after target creation -t, --target string Specify the target (e.g. 'local') -y, --yes Automatically confirm any prompts ``` diff --git a/docs/daytona_delete.md b/docs/daytona_delete.md index 33e0cdfb89..ef221eea81 100644 --- a/docs/daytona_delete.md +++ b/docs/daytona_delete.md @@ -3,7 +3,7 @@ Delete a workspace ``` -daytona delete [WORKSPACE] [flags] +daytona delete [WORKSPACE]... [flags] ``` ### Options diff --git a/docs/daytona_env.md b/docs/daytona_env.md index e036aa4314..b2af6593f9 100644 --- a/docs/daytona_env.md +++ b/docs/daytona_env.md @@ -1,6 +1,6 @@ ## daytona env -Manage profile environment variables that are added to all workspaces +Manage server environment variables that are added to all targets and workspaces ### Options inherited from parent commands @@ -11,6 +11,7 @@ Manage profile environment variables that are added to all workspaces ### SEE ALSO * [daytona](daytona.md) - Daytona is a Dev Environment Manager -* [daytona env list](daytona_env_list.md) - List profile environment variables -* [daytona env set](daytona_env_set.md) - Set profile environment variables +* [daytona env delete](daytona_env_delete.md) - Delete server environment variables +* [daytona env list](daytona_env_list.md) - List server environment variables +* [daytona env set](daytona_env_set.md) - Set server environment variables diff --git a/docs/daytona_env_delete.md b/docs/daytona_env_delete.md new file mode 100644 index 0000000000..dcb57fc792 --- /dev/null +++ b/docs/daytona_env_delete.md @@ -0,0 +1,18 @@ +## daytona env delete + +Delete server environment variables + +``` +daytona env delete [KEY]... [flags] +``` + +### Options inherited from parent commands + +``` + --help help for daytona +``` + +### SEE ALSO + +* [daytona env](daytona_env.md) - Manage server environment variables that are added to all targets and workspaces + diff --git a/docs/daytona_env_list.md b/docs/daytona_env_list.md index 86b0c1125c..600fc50a36 100644 --- a/docs/daytona_env_list.md +++ b/docs/daytona_env_list.md @@ -1,6 +1,6 @@ ## daytona env list -List profile environment variables +List server environment variables ``` daytona env list [flags] @@ -10,6 +10,7 @@ daytona env list [flags] ``` -f, --format string Output format. Must be one of (yaml, json) + -v, --show-values Show environment variable values ``` ### Options inherited from parent commands @@ -20,5 +21,5 @@ daytona env list [flags] ### SEE ALSO -* [daytona env](daytona_env.md) - Manage profile environment variables that are added to all workspaces +* [daytona env](daytona_env.md) - Manage server environment variables that are added to all targets and workspaces diff --git a/docs/daytona_env_set.md b/docs/daytona_env_set.md index ac7ed3dd5b..b5f3be05e7 100644 --- a/docs/daytona_env_set.md +++ b/docs/daytona_env_set.md @@ -1,6 +1,6 @@ ## daytona env set -Set profile environment variables +Set server environment variables ``` daytona env set [KEY=VALUE]... [flags] @@ -14,5 +14,5 @@ daytona env set [KEY=VALUE]... [flags] ### SEE ALSO -* [daytona env](daytona_env.md) - Manage profile environment variables that are added to all workspaces +* [daytona env](daytona_env.md) - Manage server environment variables that are added to all targets and workspaces diff --git a/docs/daytona_forward.md b/docs/daytona_forward.md index 46f78cb721..f07282c793 100644 --- a/docs/daytona_forward.md +++ b/docs/daytona_forward.md @@ -1,9 +1,9 @@ ## daytona forward -Forward a port from a project to your local machine +Forward a port from a workspace to your local machine ``` -daytona forward [PORT] [WORKSPACE] [PROJECT] [flags] +daytona forward [PORT] [WORKSPACE] [flags] ``` ### Options diff --git a/docs/daytona_git-provider.md b/docs/daytona_git-provider.md new file mode 100644 index 0000000000..f6e994aa80 --- /dev/null +++ b/docs/daytona_git-provider.md @@ -0,0 +1,18 @@ +## daytona git-provider + +Manage Git provider configs + +### Options inherited from parent commands + +``` + --help help for daytona +``` + +### SEE ALSO + +* [daytona](daytona.md) - Daytona is a Dev Environment Manager +* [daytona git-provider create](daytona_git-provider_create.md) - Create a Git provider config +* [daytona git-provider delete](daytona_git-provider_delete.md) - Delete a Git provider config +* [daytona git-provider list](daytona_git-provider_list.md) - Lists your registered Git provider configs +* [daytona git-provider update](daytona_git-provider_update.md) - Update a Git provider + diff --git a/docs/daytona_git-providers_add.md b/docs/daytona_git-provider_create.md similarity index 67% rename from docs/daytona_git-providers_add.md rename to docs/daytona_git-provider_create.md index 88deff5d95..6e0e1c827c 100644 --- a/docs/daytona_git-providers_add.md +++ b/docs/daytona_git-provider_create.md @@ -1,9 +1,9 @@ -## daytona git-providers add +## daytona git-provider create -Register a Git provider +Create a Git provider config ``` -daytona git-providers add [GIT_PROVIDER_ID] [flags] +daytona git-provider create [GIT_PROVIDER_ID] [flags] ``` ### Options @@ -25,5 +25,5 @@ daytona git-providers add [GIT_PROVIDER_ID] [flags] ### SEE ALSO -* [daytona git-providers](daytona_git-providers.md) - Manage Git providers +* [daytona git-provider](daytona_git-provider.md) - Manage Git provider configs diff --git a/docs/daytona_git-provider_delete.md b/docs/daytona_git-provider_delete.md new file mode 100644 index 0000000000..05b1c52a49 --- /dev/null +++ b/docs/daytona_git-provider_delete.md @@ -0,0 +1,25 @@ +## daytona git-provider delete + +Delete a Git provider config + +``` +daytona git-provider delete [flags] +``` + +### Options + +``` + -a, --all Delete all Git providers + -y, --yes Confirm deletion without prompt +``` + +### Options inherited from parent commands + +``` + --help help for daytona +``` + +### SEE ALSO + +* [daytona git-provider](daytona_git-provider.md) - Manage Git provider configs + diff --git a/docs/daytona_git-provider_list.md b/docs/daytona_git-provider_list.md new file mode 100644 index 0000000000..b1ab54dadb --- /dev/null +++ b/docs/daytona_git-provider_list.md @@ -0,0 +1,24 @@ +## daytona git-provider list + +Lists your registered Git provider configs + +``` +daytona git-provider list [flags] +``` + +### Options + +``` + -f, --format string Output format. Must be one of (yaml, json) +``` + +### Options inherited from parent commands + +``` + --help help for daytona +``` + +### SEE ALSO + +* [daytona git-provider](daytona_git-provider.md) - Manage Git provider configs + diff --git a/docs/daytona_git-provider_update.md b/docs/daytona_git-provider_update.md new file mode 100644 index 0000000000..b768a04ddb --- /dev/null +++ b/docs/daytona_git-provider_update.md @@ -0,0 +1,18 @@ +## daytona git-provider update + +Update a Git provider + +``` +daytona git-provider update [flags] +``` + +### Options inherited from parent commands + +``` + --help help for daytona +``` + +### SEE ALSO + +* [daytona git-provider](daytona_git-provider.md) - Manage Git provider configs + diff --git a/docs/daytona_git-providers.md b/docs/daytona_git-providers.md deleted file mode 100644 index 702fdac3a3..0000000000 --- a/docs/daytona_git-providers.md +++ /dev/null @@ -1,18 +0,0 @@ -## daytona git-providers - -Manage Git providers - -### Options inherited from parent commands - -``` - --help help for daytona -``` - -### SEE ALSO - -* [daytona](daytona.md) - Daytona is a Dev Environment Manager -* [daytona git-providers add](daytona_git-providers_add.md) - Register a Git provider -* [daytona git-providers delete](daytona_git-providers_delete.md) - Unregister a Git provider -* [daytona git-providers list](daytona_git-providers_list.md) - Lists your registered Git providers -* [daytona git-providers update](daytona_git-providers_update.md) - Update a Git provider - diff --git a/docs/daytona_git-providers_delete.md b/docs/daytona_git-providers_delete.md deleted file mode 100644 index ab7a22aa23..0000000000 --- a/docs/daytona_git-providers_delete.md +++ /dev/null @@ -1,25 +0,0 @@ -## daytona git-providers delete - -Unregister a Git provider - -``` -daytona git-providers delete [flags] -``` - -### Options - -``` - -a, --all Remove all Git providers - -y, --yes Confirm deletion without prompt -``` - -### Options inherited from parent commands - -``` - --help help for daytona -``` - -### SEE ALSO - -* [daytona git-providers](daytona_git-providers.md) - Manage Git providers - diff --git a/docs/daytona_git-providers_update.md b/docs/daytona_git-providers_update.md deleted file mode 100644 index 164f00de24..0000000000 --- a/docs/daytona_git-providers_update.md +++ /dev/null @@ -1,18 +0,0 @@ -## daytona git-providers update - -Update a Git provider - -``` -daytona git-providers update [flags] -``` - -### Options inherited from parent commands - -``` - --help help for daytona -``` - -### SEE ALSO - -* [daytona git-providers](daytona_git-providers.md) - Manage Git providers - diff --git a/docs/daytona_list.md b/docs/daytona_list.md index ea33021b05..10e0f9405b 100644 --- a/docs/daytona_list.md +++ b/docs/daytona_list.md @@ -10,7 +10,7 @@ daytona list [flags] ``` -f, --format string Output format. Must be one of (yaml, json) - -v, --verbose Show verbose output + -l, --label strings Filter by label ``` ### Options inherited from parent commands diff --git a/docs/daytona_logs.md b/docs/daytona_logs.md index 37aec822e8..4826bdd139 100644 --- a/docs/daytona_logs.md +++ b/docs/daytona_logs.md @@ -1,16 +1,15 @@ ## daytona logs -View logs for a workspace/project +View the logs of a workspace ``` -daytona logs [WORKSPACE] [PROJECT_NAME] [flags] +daytona logs [WORKSPACE] [flags] ``` ### Options ``` - -f, --follow Follow logs - -w, --workspace View workspace logs + -f, --follow Follow logs ``` ### Options inherited from parent commands diff --git a/docs/daytona_prebuild.md b/docs/daytona_prebuild.md index 8fbe49c684..ed17fef4a9 100644 --- a/docs/daytona_prebuild.md +++ b/docs/daytona_prebuild.md @@ -11,7 +11,7 @@ Manage prebuilds ### SEE ALSO * [daytona](daytona.md) - Daytona is a Dev Environment Manager -* [daytona prebuild add](daytona_prebuild_add.md) - Add a prebuild configuration +* [daytona prebuild create](daytona_prebuild_create.md) - Create a prebuild configuration * [daytona prebuild delete](daytona_prebuild_delete.md) - Delete a prebuild configuration * [daytona prebuild info](daytona_prebuild_info.md) - Show prebuild configuration info * [daytona prebuild list](daytona_prebuild_list.md) - List prebuild configurations diff --git a/docs/daytona_prebuild_add.md b/docs/daytona_prebuild_create.md similarity index 84% rename from docs/daytona_prebuild_add.md rename to docs/daytona_prebuild_create.md index bfdcb38aa5..1ae54acafe 100644 --- a/docs/daytona_prebuild_add.md +++ b/docs/daytona_prebuild_create.md @@ -1,9 +1,9 @@ -## daytona prebuild add +## daytona prebuild create -Add a prebuild configuration +Create a prebuild configuration ``` -daytona prebuild add [PROJECT_CONFIG] [flags] +daytona prebuild create [WORKSPACE_CONFIG] [flags] ``` ### Options diff --git a/docs/daytona_prebuild_delete.md b/docs/daytona_prebuild_delete.md index 3b887b4158..56e5d4015e 100644 --- a/docs/daytona_prebuild_delete.md +++ b/docs/daytona_prebuild_delete.md @@ -3,7 +3,7 @@ Delete a prebuild configuration ``` -daytona prebuild delete [PROJECT_CONFIG] [PREBUILD] [flags] +daytona prebuild delete [WORKSPACE_CONFIG] [PREBUILD] [flags] ``` ### Options diff --git a/docs/daytona_prebuild_update.md b/docs/daytona_prebuild_update.md index ae85a83a36..1b735fecef 100644 --- a/docs/daytona_prebuild_update.md +++ b/docs/daytona_prebuild_update.md @@ -3,7 +3,7 @@ Update a prebuild configuration ``` -daytona prebuild update [PROJECT_CONFIG] [PREBUILD_ID] [flags] +daytona prebuild update [WORKSPACE_CONFIG] [PREBUILD_ID] [flags] ``` ### Options diff --git a/docs/daytona_profile.md b/docs/daytona_profile.md index 2226adeae0..819d91d7b2 100644 --- a/docs/daytona_profile.md +++ b/docs/daytona_profile.md @@ -11,9 +11,9 @@ Manage profiles ### SEE ALSO * [daytona](daytona.md) - Daytona is a Dev Environment Manager -* [daytona profile add](daytona_profile_add.md) - Add profile -* [daytona profile delete](daytona_profile_delete.md) - Delete profile [PROFILE_NAME] -* [daytona profile edit](daytona_profile_edit.md) - Edit profile [PROFILE_NAME] +* [daytona profile create](daytona_profile_create.md) - Create a profile +* [daytona profile delete](daytona_profile_delete.md) - Delete a profile * [daytona profile list](daytona_profile_list.md) - List profiles +* [daytona profile update](daytona_profile_update.md) - Update profile [PROFILE_NAME] * [daytona profile use](daytona_profile_use.md) - Use profile [PROFILE_NAME] diff --git a/docs/daytona_profile_add.md b/docs/daytona_profile_create.md similarity index 80% rename from docs/daytona_profile_add.md rename to docs/daytona_profile_create.md index 12ea0fa96d..c831592df7 100644 --- a/docs/daytona_profile_add.md +++ b/docs/daytona_profile_create.md @@ -1,9 +1,9 @@ -## daytona profile add +## daytona profile create -Add profile +Create a profile ``` -daytona profile add [flags] +daytona profile create [flags] ``` ### Options diff --git a/docs/daytona_profile_delete.md b/docs/daytona_profile_delete.md index d8ed86d359..1118f7559a 100644 --- a/docs/daytona_profile_delete.md +++ b/docs/daytona_profile_delete.md @@ -1,9 +1,9 @@ ## daytona profile delete -Delete profile [PROFILE_NAME] +Delete a profile ``` -daytona profile delete [flags] +daytona profile delete [PROFILE_NAME] [flags] ``` ### Options inherited from parent commands diff --git a/docs/daytona_profile_edit.md b/docs/daytona_profile_update.md similarity index 77% rename from docs/daytona_profile_edit.md rename to docs/daytona_profile_update.md index 79be7454f4..ba44c251cc 100644 --- a/docs/daytona_profile_edit.md +++ b/docs/daytona_profile_update.md @@ -1,9 +1,9 @@ -## daytona profile edit +## daytona profile update -Edit profile [PROFILE_NAME] +Update profile [PROFILE_NAME] ``` -daytona profile edit [flags] +daytona profile update [flags] ``` ### Options diff --git a/docs/daytona_project-config.md b/docs/daytona_project-config.md deleted file mode 100644 index 59f335322b..0000000000 --- a/docs/daytona_project-config.md +++ /dev/null @@ -1,22 +0,0 @@ -## daytona project-config - -Manage project configs - -### Options inherited from parent commands - -``` - --help help for daytona -``` - -### SEE ALSO - -* [daytona](daytona.md) - Daytona is a Dev Environment Manager -* [daytona project-config add](daytona_project-config_add.md) - Add a project config -* [daytona project-config delete](daytona_project-config_delete.md) - Delete a project config -* [daytona project-config export](daytona_project-config_export.md) - Export a project config -* [daytona project-config import](daytona_project-config_import.md) - Import project config from JSON -* [daytona project-config info](daytona_project-config_info.md) - Show project config info -* [daytona project-config list](daytona_project-config_list.md) - Lists project configs -* [daytona project-config set-default](daytona_project-config_set-default.md) - Set project config info -* [daytona project-config update](daytona_project-config_update.md) - Update a project config - diff --git a/docs/daytona_project-config_add.md b/docs/daytona_project-config_add.md deleted file mode 100644 index 3204ef80ce..0000000000 --- a/docs/daytona_project-config_add.md +++ /dev/null @@ -1,31 +0,0 @@ -## daytona project-config add - -Add a project config - -``` -daytona project-config add [flags] -``` - -### Options - -``` - --builder BuildChoice Specify the builder (currently auto/devcontainer/none) - --custom-image string Create the project with the custom image passed as the flag value; Requires setting --custom-image-user flag as well - --custom-image-user string Create the project with the custom image user passed as the flag value; Requires setting --custom-image flag as well - --devcontainer-path string Automatically assign the devcontainer builder with the path passed as the flag value - --env stringArray Specify environment variables (e.g. --env 'KEY1=VALUE1' --env 'KEY2=VALUE2' ...') - --git-provider-config string Specify the Git provider configuration ID or alias - --manual Manually enter the Git repository - --name string Specify the project config name -``` - -### Options inherited from parent commands - -``` - --help help for daytona -``` - -### SEE ALSO - -* [daytona project-config](daytona_project-config.md) - Manage project configs - diff --git a/docs/daytona_project-config_export.md b/docs/daytona_project-config_export.md deleted file mode 100644 index 312d85811a..0000000000 --- a/docs/daytona_project-config_export.md +++ /dev/null @@ -1,25 +0,0 @@ -## daytona project-config export - -Export a project config - -``` -daytona project-config export [flags] -``` - -### Options - -``` - -a, --all Export all project configs - -f, --format string Output format. Must be one of (yaml, json) -``` - -### Options inherited from parent commands - -``` - --help help for daytona -``` - -### SEE ALSO - -* [daytona project-config](daytona_project-config.md) - Manage project configs - diff --git a/docs/daytona_project-config_import.md b/docs/daytona_project-config_import.md deleted file mode 100644 index 89e0cbfd31..0000000000 --- a/docs/daytona_project-config_import.md +++ /dev/null @@ -1,24 +0,0 @@ -## daytona project-config import - -Import project config from JSON - -``` -daytona project-config import [flags] -``` - -### Options - -``` - -f, --file string Import project config from a JSON file. Use '-' to read from stdin. -``` - -### Options inherited from parent commands - -``` - --help help for daytona -``` - -### SEE ALSO - -* [daytona project-config](daytona_project-config.md) - Manage project configs - diff --git a/docs/daytona_project-config_set-default.md b/docs/daytona_project-config_set-default.md deleted file mode 100644 index a2561d03d0..0000000000 --- a/docs/daytona_project-config_set-default.md +++ /dev/null @@ -1,18 +0,0 @@ -## daytona project-config set-default - -Set project config info - -``` -daytona project-config set-default [flags] -``` - -### Options inherited from parent commands - -``` - --help help for daytona -``` - -### SEE ALSO - -* [daytona project-config](daytona_project-config.md) - Manage project configs - diff --git a/docs/daytona_project-config_update.md b/docs/daytona_project-config_update.md deleted file mode 100644 index c78a16cb1c..0000000000 --- a/docs/daytona_project-config_update.md +++ /dev/null @@ -1,18 +0,0 @@ -## daytona project-config update - -Update a project config - -``` -daytona project-config update [flags] -``` - -### Options inherited from parent commands - -``` - --help help for daytona -``` - -### SEE ALSO - -* [daytona project-config](daytona_project-config.md) - Manage project configs - diff --git a/docs/daytona_purge.md b/docs/daytona_purge.md index 0084e0a5e5..0b9b699151 100644 --- a/docs/daytona_purge.md +++ b/docs/daytona_purge.md @@ -4,7 +4,7 @@ Purges all Daytona data from the current device ### Synopsis -Purges all Daytona data from the current device - including all workspaces, configuration files, and SSH files. This command is irreversible. +Purges all Daytona data from the current device - including all local runner providers, configuration files and SSH files. This command is irreversible. ``` daytona purge [flags] @@ -13,8 +13,8 @@ daytona purge [flags] ### Options ``` - -f, --force Delete all workspaces by force - -y, --yes Execute purge without prompt + -f, --force Delete all targets by force + -y, --yes Execute purge without a prompt ``` ### Options inherited from parent commands diff --git a/docs/daytona_restart.md b/docs/daytona_restart.md index bdbcac3bfa..9aa98ed36a 100644 --- a/docs/daytona_restart.md +++ b/docs/daytona_restart.md @@ -3,13 +3,7 @@ Restart a workspace ``` -daytona restart [WORKSPACE] [flags] -``` - -### Options - -``` - -p, --project string Restart a single project in the workspace (project name) +daytona restart [WORKSPACE]... [flags] ``` ### Options inherited from parent commands diff --git a/docs/daytona_runner.md b/docs/daytona_runner.md new file mode 100644 index 0000000000..a4f0b6fb5a --- /dev/null +++ b/docs/daytona_runner.md @@ -0,0 +1,22 @@ +## daytona runner + +Manage the runner + +### Options inherited from parent commands + +``` + --help help for daytona +``` + +### SEE ALSO + +* [daytona](daytona.md) - Daytona is a Dev Environment Manager +* [daytona runner config](daytona_runner_config.md) - Outputs Daytona Runner config +* [daytona runner configure](daytona_runner_configure.md) - Configure Daytona Runner +* [daytona runner logs](daytona_runner_logs.md) - View runner logs +* [daytona runner purge](daytona_runner_purge.md) - Purges the Daytona Runner +* [daytona runner restart](daytona_runner_restart.md) - Restarts the runner +* [daytona runner serve](daytona_runner_serve.md) - Starts the runner in the foreground +* [daytona runner start](daytona_runner_start.md) - Starts the runner +* [daytona runner stop](daytona_runner_stop.md) - Stops the runner + diff --git a/docs/daytona_runner_config.md b/docs/daytona_runner_config.md new file mode 100644 index 0000000000..95ba355f15 --- /dev/null +++ b/docs/daytona_runner_config.md @@ -0,0 +1,25 @@ +## daytona runner config + +Outputs Daytona Runner config + +``` +daytona runner config [flags] +``` + +### Options + +``` + -f, --format string Output format. Must be one of (yaml, json) + -k, --key Show API Key +``` + +### Options inherited from parent commands + +``` + --help help for daytona +``` + +### SEE ALSO + +* [daytona runner](daytona_runner.md) - Manage the runner + diff --git a/docs/daytona_runner_configure.md b/docs/daytona_runner_configure.md new file mode 100644 index 0000000000..f9743af8bc --- /dev/null +++ b/docs/daytona_runner_configure.md @@ -0,0 +1,29 @@ +## daytona runner configure + +Configure Daytona Runner + +``` +daytona runner configure [flags] +``` + +### Options + +``` + --api-key string Runner API Key + --api-url string Daytona Server API URL + --client-id string Client ID + --disable-telemetry Disable telemetry + --id string Runner ID + --name string Runner Name +``` + +### Options inherited from parent commands + +``` + --help help for daytona +``` + +### SEE ALSO + +* [daytona runner](daytona_runner.md) - Manage the runner + diff --git a/docs/daytona_runner_logs.md b/docs/daytona_runner_logs.md new file mode 100644 index 0000000000..5c357d7578 --- /dev/null +++ b/docs/daytona_runner_logs.md @@ -0,0 +1,24 @@ +## daytona runner logs + +View runner logs + +``` +daytona runner logs [flags] +``` + +### Options + +``` + -f, --follow Follow logs +``` + +### Options inherited from parent commands + +``` + --help help for daytona +``` + +### SEE ALSO + +* [daytona runner](daytona_runner.md) - Manage the runner + diff --git a/docs/daytona_runner_purge.md b/docs/daytona_runner_purge.md new file mode 100644 index 0000000000..19ea313d08 --- /dev/null +++ b/docs/daytona_runner_purge.md @@ -0,0 +1,24 @@ +## daytona runner purge + +Purges the Daytona Runner + +``` +daytona runner purge [flags] +``` + +### Options + +``` + -y, --yes Execute Daytona Runner purge without a prompt +``` + +### Options inherited from parent commands + +``` + --help help for daytona +``` + +### SEE ALSO + +* [daytona runner](daytona_runner.md) - Manage the runner + diff --git a/docs/daytona_runner_restart.md b/docs/daytona_runner_restart.md new file mode 100644 index 0000000000..25274c3682 --- /dev/null +++ b/docs/daytona_runner_restart.md @@ -0,0 +1,18 @@ +## daytona runner restart + +Restarts the runner + +``` +daytona runner restart [flags] +``` + +### Options inherited from parent commands + +``` + --help help for daytona +``` + +### SEE ALSO + +* [daytona runner](daytona_runner.md) - Manage the runner + diff --git a/docs/daytona_runner_serve.md b/docs/daytona_runner_serve.md new file mode 100644 index 0000000000..42f9d6ea26 --- /dev/null +++ b/docs/daytona_runner_serve.md @@ -0,0 +1,18 @@ +## daytona runner serve + +Starts the runner in the foreground + +``` +daytona runner serve [flags] +``` + +### Options inherited from parent commands + +``` + --help help for daytona +``` + +### SEE ALSO + +* [daytona runner](daytona_runner.md) - Manage the runner + diff --git a/docs/daytona_runner_start.md b/docs/daytona_runner_start.md new file mode 100644 index 0000000000..3cbe65bcc8 --- /dev/null +++ b/docs/daytona_runner_start.md @@ -0,0 +1,18 @@ +## daytona runner start + +Starts the runner + +``` +daytona runner start [flags] +``` + +### Options inherited from parent commands + +``` + --help help for daytona +``` + +### SEE ALSO + +* [daytona runner](daytona_runner.md) - Manage the runner + diff --git a/docs/daytona_runner_stop.md b/docs/daytona_runner_stop.md new file mode 100644 index 0000000000..3a5aeba7fc --- /dev/null +++ b/docs/daytona_runner_stop.md @@ -0,0 +1,18 @@ +## daytona runner stop + +Stops the runner + +``` +daytona runner stop [flags] +``` + +### Options inherited from parent commands + +``` + --help help for daytona +``` + +### SEE ALSO + +* [daytona runner](daytona_runner.md) - Manage the runner + diff --git a/docs/daytona_server.md b/docs/daytona_server.md index bffb71a5e9..01c5ec5a19 100644 --- a/docs/daytona_server.md +++ b/docs/daytona_server.md @@ -25,6 +25,7 @@ daytona server [flags] * [daytona server configure](daytona_server_configure.md) - Configure Daytona Server * [daytona server logs](daytona_server_logs.md) - Output Daytona Server logs * [daytona server restart](daytona_server_restart.md) - Restarts the Daytona Server daemon +* [daytona server runner](daytona_server_runner.md) - Manage runners * [daytona server start](daytona_server_start.md) - Start the Daytona Server daemon * [daytona server stop](daytona_server_stop.md) - Stops the Daytona Server daemon diff --git a/docs/daytona_server_runner.md b/docs/daytona_server_runner.md new file mode 100644 index 0000000000..3080769590 --- /dev/null +++ b/docs/daytona_server_runner.md @@ -0,0 +1,18 @@ +## daytona server runner + +Manage runners + +### Options inherited from parent commands + +``` + --help help for daytona +``` + +### SEE ALSO + +* [daytona server](daytona_server.md) - Start the server process in daemon mode +* [daytona server runner create](daytona_server_runner_create.md) - Create a runner +* [daytona server runner delete](daytona_server_runner_delete.md) - Delete a runner +* [daytona server runner list](daytona_server_runner_list.md) - List runners +* [daytona server runner logs](daytona_server_runner_logs.md) - View runner logs + diff --git a/docs/daytona_server_runner_create.md b/docs/daytona_server_runner_create.md new file mode 100644 index 0000000000..efaedb9ea2 --- /dev/null +++ b/docs/daytona_server_runner_create.md @@ -0,0 +1,24 @@ +## daytona server runner create + +Create a runner + +``` +daytona server runner create [flags] +``` + +### Options + +``` + -n, --name string Runner name +``` + +### Options inherited from parent commands + +``` + --help help for daytona +``` + +### SEE ALSO + +* [daytona server runner](daytona_server_runner.md) - Manage runners + diff --git a/docs/daytona_server_runner_delete.md b/docs/daytona_server_runner_delete.md new file mode 100644 index 0000000000..48434a37e8 --- /dev/null +++ b/docs/daytona_server_runner_delete.md @@ -0,0 +1,24 @@ +## daytona server runner delete + +Delete a runner + +``` +daytona server runner delete [RUNNER] [flags] +``` + +### Options + +``` + -y, --yes Confirm deletion without prompt +``` + +### Options inherited from parent commands + +``` + --help help for daytona +``` + +### SEE ALSO + +* [daytona server runner](daytona_server_runner.md) - Manage runners + diff --git a/docs/daytona_project-config_list.md b/docs/daytona_server_runner_list.md similarity index 54% rename from docs/daytona_project-config_list.md rename to docs/daytona_server_runner_list.md index 10078c2302..eea0953595 100644 --- a/docs/daytona_project-config_list.md +++ b/docs/daytona_server_runner_list.md @@ -1,9 +1,9 @@ -## daytona project-config list +## daytona server runner list -Lists project configs +List runners ``` -daytona project-config list [flags] +daytona server runner list [flags] ``` ### Options @@ -20,5 +20,5 @@ daytona project-config list [flags] ### SEE ALSO -* [daytona project-config](daytona_project-config.md) - Manage project configs +* [daytona server runner](daytona_server_runner.md) - Manage runners diff --git a/docs/daytona_server_runner_logs.md b/docs/daytona_server_runner_logs.md new file mode 100644 index 0000000000..3ac3c06e45 --- /dev/null +++ b/docs/daytona_server_runner_logs.md @@ -0,0 +1,24 @@ +## daytona server runner logs + +View runner logs + +``` +daytona server runner logs [RUNNER_ID] [flags] +``` + +### Options + +``` + -f, --follow Follow logs +``` + +### Options inherited from parent commands + +``` + --help help for daytona +``` + +### SEE ALSO + +* [daytona server runner](daytona_server_runner.md) - Manage runners + diff --git a/docs/daytona_ssh.md b/docs/daytona_ssh.md index bebc98cf93..653eefb918 100644 --- a/docs/daytona_ssh.md +++ b/docs/daytona_ssh.md @@ -1,15 +1,15 @@ ## daytona ssh -SSH into a project using the terminal +SSH into a workspace using the terminal ``` -daytona ssh [WORKSPACE] [PROJECT] [CMD...] [flags] +daytona ssh [WORKSPACE] [CMD...] [flags] ``` ### Options ``` - -e, --edit Edit the project's SSH config + -e, --edit Edit the workspace's SSH config -o, --option stringArray Specify SSH options in KEY=VALUE format. -y, --yes Automatically confirm any prompts ``` diff --git a/docs/daytona_start.md b/docs/daytona_start.md index 3680dafb9a..a176da8837 100644 --- a/docs/daytona_start.md +++ b/docs/daytona_start.md @@ -3,16 +3,15 @@ Start a workspace ``` -daytona start [WORKSPACE] [flags] +daytona start [WORKSPACE]... [flags] ``` ### Options ``` - -a, --all Start all workspaces - -c, --code Open the workspace in the IDE after workspace start - -p, --project string Start a single project in the workspace (project name) - -y, --yes Automatically confirm any prompts + -a, --all Start all targets + -c, --code Open the target in the IDE after target start + -y, --yes Automatically confirm any prompts ``` ### Options inherited from parent commands diff --git a/docs/daytona_stop.md b/docs/daytona_stop.md index 864aa738a6..f44baec41b 100644 --- a/docs/daytona_stop.md +++ b/docs/daytona_stop.md @@ -3,14 +3,14 @@ Stop a workspace ``` -daytona stop [WORKSPACE] [flags] +daytona stop [WORKSPACE]... [flags] ``` ### Options ``` - -a, --all Stop all workspaces - -p, --project string Stop a single project in the workspace (project name) + -a, --all Stop all targets + -y, --yes Automatically confirm any prompts ``` ### Options inherited from parent commands diff --git a/docs/daytona_target-config.md b/docs/daytona_target-config.md new file mode 100644 index 0000000000..1903037058 --- /dev/null +++ b/docs/daytona_target-config.md @@ -0,0 +1,17 @@ +## daytona target-config + +Manage target configs + +### Options inherited from parent commands + +``` + --help help for daytona +``` + +### SEE ALSO + +* [daytona](daytona.md) - Daytona is a Dev Environment Manager +* [daytona target-config create](daytona_target-config_create.md) - Create target config +* [daytona target-config delete](daytona_target-config_delete.md) - Deletes a target config +* [daytona target-config list](daytona_target-config_list.md) - List target configs + diff --git a/docs/daytona_target_set.md b/docs/daytona_target-config_create.md similarity index 57% rename from docs/daytona_target_set.md rename to docs/daytona_target-config_create.md index c7bf440d4d..3b621e7078 100644 --- a/docs/daytona_target_set.md +++ b/docs/daytona_target-config_create.md @@ -1,9 +1,9 @@ -## daytona target set +## daytona target-config create -Set provider target +Create target config ``` -daytona target set [flags] +daytona target-config create [flags] ``` ### Options @@ -20,5 +20,5 @@ daytona target set [flags] ### SEE ALSO -* [daytona target](daytona_target.md) - Manage provider targets +* [daytona target-config](daytona_target-config.md) - Manage target configs diff --git a/docs/daytona_target-config_delete.md b/docs/daytona_target-config_delete.md new file mode 100644 index 0000000000..2c0c89f2e3 --- /dev/null +++ b/docs/daytona_target-config_delete.md @@ -0,0 +1,24 @@ +## daytona target-config delete + +Deletes a target config + +``` +daytona target-config delete [TARGET_CONFIG] [flags] +``` + +### Options + +``` + -y, --yes Confirm deletion of all targets without prompt +``` + +### Options inherited from parent commands + +``` + --help help for daytona +``` + +### SEE ALSO + +* [daytona target-config](daytona_target-config.md) - Manage target configs + diff --git a/docs/daytona_target-config_list.md b/docs/daytona_target-config_list.md new file mode 100644 index 0000000000..7eb1d87777 --- /dev/null +++ b/docs/daytona_target-config_list.md @@ -0,0 +1,25 @@ +## daytona target-config list + +List target configs + +``` +daytona target-config list [flags] +``` + +### Options + +``` + -f, --format string Output format. Must be one of (yaml, json) + -v, --show-options Show target options +``` + +### Options inherited from parent commands + +``` + --help help for daytona +``` + +### SEE ALSO + +* [daytona target-config](daytona_target-config.md) - Manage target configs + diff --git a/docs/daytona_target.md b/docs/daytona_target.md index 32b4b9f7f3..2470776308 100644 --- a/docs/daytona_target.md +++ b/docs/daytona_target.md @@ -1,6 +1,6 @@ ## daytona target -Manage provider targets +Manage targets ### Options inherited from parent commands @@ -11,8 +11,14 @@ Manage provider targets ### SEE ALSO * [daytona](daytona.md) - Daytona is a Dev Environment Manager +* [daytona target create](daytona_target_create.md) - Create a target +* [daytona target delete](daytona_target_delete.md) - Delete a target +* [daytona target info](daytona_target_info.md) - Show target info * [daytona target list](daytona_target_list.md) - List targets -* [daytona target remove](daytona_target_remove.md) - Remove target -* [daytona target set](daytona_target_set.md) - Set provider target -* [daytona target set-default](daytona_target_set-default.md) - Set target to be used by default +* [daytona target logs](daytona_target_logs.md) - View the logs of a target +* [daytona target restart](daytona_target_restart.md) - Restart a target +* [daytona target set-default](daytona_target_set-default.md) - Set default target +* [daytona target ssh](daytona_target_ssh.md) - SSH into a target using the terminal +* [daytona target start](daytona_target_start.md) - Start a target +* [daytona target stop](daytona_target_stop.md) - Stop a target diff --git a/docs/daytona_target_create.md b/docs/daytona_target_create.md new file mode 100644 index 0000000000..68129d015d --- /dev/null +++ b/docs/daytona_target_create.md @@ -0,0 +1,18 @@ +## daytona target create + +Create a target + +``` +daytona target create [flags] +``` + +### Options inherited from parent commands + +``` + --help help for daytona +``` + +### SEE ALSO + +* [daytona target](daytona_target.md) - Manage targets + diff --git a/docs/daytona_target_delete.md b/docs/daytona_target_delete.md new file mode 100644 index 0000000000..6400ed112b --- /dev/null +++ b/docs/daytona_target_delete.md @@ -0,0 +1,26 @@ +## daytona target delete + +Delete a target + +``` +daytona target delete [TARGET]... [flags] +``` + +### Options + +``` + -a, --all Delete all targets + -f, --force Delete a target by force + -y, --yes Confirm deletion without prompt +``` + +### Options inherited from parent commands + +``` + --help help for daytona +``` + +### SEE ALSO + +* [daytona target](daytona_target.md) - Manage targets + diff --git a/docs/daytona_git-providers_list.md b/docs/daytona_target_info.md similarity index 53% rename from docs/daytona_git-providers_list.md rename to docs/daytona_target_info.md index a99673badb..911d8c7126 100644 --- a/docs/daytona_git-providers_list.md +++ b/docs/daytona_target_info.md @@ -1,15 +1,16 @@ -## daytona git-providers list +## daytona target info -Lists your registered Git providers +Show target info ``` -daytona git-providers list [flags] +daytona target info [TARGET] [flags] ``` ### Options ``` -f, --format string Output format. Must be one of (yaml, json) + -v, --show-options Show target options ``` ### Options inherited from parent commands @@ -20,5 +21,5 @@ daytona git-providers list [flags] ### SEE ALSO -* [daytona git-providers](daytona_git-providers.md) - Manage Git providers +* [daytona target](daytona_target.md) - Manage targets diff --git a/docs/daytona_target_list.md b/docs/daytona_target_list.md index 286cd46b2a..7a88340dc5 100644 --- a/docs/daytona_target_list.md +++ b/docs/daytona_target_list.md @@ -10,6 +10,7 @@ daytona target list [flags] ``` -f, --format string Output format. Must be one of (yaml, json) + -v, --show-options Show target options ``` ### Options inherited from parent commands @@ -20,5 +21,5 @@ daytona target list [flags] ### SEE ALSO -* [daytona target](daytona_target.md) - Manage provider targets +* [daytona target](daytona_target.md) - Manage targets diff --git a/docs/daytona_target_logs.md b/docs/daytona_target_logs.md new file mode 100644 index 0000000000..68fc5f8f49 --- /dev/null +++ b/docs/daytona_target_logs.md @@ -0,0 +1,24 @@ +## daytona target logs + +View the logs of a target + +``` +daytona target logs [TARGET] [flags] +``` + +### Options + +``` + -f, --follow Follow logs +``` + +### Options inherited from parent commands + +``` + --help help for daytona +``` + +### SEE ALSO + +* [daytona target](daytona_target.md) - Manage targets + diff --git a/docs/daytona_target_remove.md b/docs/daytona_target_remove.md deleted file mode 100644 index 2d6828fcbc..0000000000 --- a/docs/daytona_target_remove.md +++ /dev/null @@ -1,24 +0,0 @@ -## daytona target remove - -Remove target - -``` -daytona target remove [TARGET_NAME] [flags] -``` - -### Options - -``` - -y, --yes Confirm deletion of all workspaces without prompt -``` - -### Options inherited from parent commands - -``` - --help help for daytona -``` - -### SEE ALSO - -* [daytona target](daytona_target.md) - Manage provider targets - diff --git a/docs/daytona_target_restart.md b/docs/daytona_target_restart.md new file mode 100644 index 0000000000..d31dbdbff8 --- /dev/null +++ b/docs/daytona_target_restart.md @@ -0,0 +1,18 @@ +## daytona target restart + +Restart a target + +``` +daytona target restart [TARGET] [flags] +``` + +### Options inherited from parent commands + +``` + --help help for daytona +``` + +### SEE ALSO + +* [daytona target](daytona_target.md) - Manage targets + diff --git a/docs/daytona_target_set-default.md b/docs/daytona_target_set-default.md index d37fb3155c..b6ad2fea8a 100644 --- a/docs/daytona_target_set-default.md +++ b/docs/daytona_target_set-default.md @@ -1,9 +1,9 @@ ## daytona target set-default -Set target to be used by default +Set default target ``` -daytona target set-default [TARGET_NAME] [flags] +daytona target set-default [TARGET] [flags] ``` ### Options inherited from parent commands @@ -14,5 +14,5 @@ daytona target set-default [TARGET_NAME] [flags] ### SEE ALSO -* [daytona target](daytona_target.md) - Manage provider targets +* [daytona target](daytona_target.md) - Manage targets diff --git a/docs/daytona_target_ssh.md b/docs/daytona_target_ssh.md new file mode 100644 index 0000000000..b1640a613e --- /dev/null +++ b/docs/daytona_target_ssh.md @@ -0,0 +1,25 @@ +## daytona target ssh + +SSH into a target using the terminal + +``` +daytona target ssh [TARGET] [CMD...] [flags] +``` + +### Options + +``` + -o, --option stringArray Specify SSH options in KEY=VALUE format. + -y, --yes Automatically confirm any prompts +``` + +### Options inherited from parent commands + +``` + --help help for daytona +``` + +### SEE ALSO + +* [daytona target](daytona_target.md) - Manage targets + diff --git a/docs/daytona_target_start.md b/docs/daytona_target_start.md new file mode 100644 index 0000000000..7fd21e4873 --- /dev/null +++ b/docs/daytona_target_start.md @@ -0,0 +1,25 @@ +## daytona target start + +Start a target + +``` +daytona target start [TARGET] [flags] +``` + +### Options + +``` + -a, --all Start all targets + -y, --yes Automatically confirm any prompts +``` + +### Options inherited from parent commands + +``` + --help help for daytona +``` + +### SEE ALSO + +* [daytona target](daytona_target.md) - Manage targets + diff --git a/docs/daytona_target_stop.md b/docs/daytona_target_stop.md new file mode 100644 index 0000000000..714942afcb --- /dev/null +++ b/docs/daytona_target_stop.md @@ -0,0 +1,24 @@ +## daytona target stop + +Stop a target + +``` +daytona target stop [TARGET] [flags] +``` + +### Options + +``` + -a, --all Stop all targets +``` + +### Options inherited from parent commands + +``` + --help help for daytona +``` + +### SEE ALSO + +* [daytona target](daytona_target.md) - Manage targets + diff --git a/docs/daytona_template.md b/docs/daytona_template.md new file mode 100644 index 0000000000..355d11cb70 --- /dev/null +++ b/docs/daytona_template.md @@ -0,0 +1,22 @@ +## daytona template + +Manage workspace templates + +### Options inherited from parent commands + +``` + --help help for daytona +``` + +### SEE ALSO + +* [daytona](daytona.md) - Daytona is a Dev Environment Manager +* [daytona template create](daytona_template_create.md) - Create a workspace template +* [daytona template delete](daytona_template_delete.md) - Delete a workspace template +* [daytona template export](daytona_template_export.md) - Export a workspace template +* [daytona template import](daytona_template_import.md) - Import a workspace template from a JSON object +* [daytona template info](daytona_template_info.md) - Show workspace template info +* [daytona template list](daytona_template_list.md) - Lists workspace templates +* [daytona template set-default](daytona_template_set-default.md) - Set workspace template info +* [daytona template update](daytona_template_update.md) - Update a workspace template + diff --git a/docs/daytona_template_create.md b/docs/daytona_template_create.md new file mode 100644 index 0000000000..71042ed4f2 --- /dev/null +++ b/docs/daytona_template_create.md @@ -0,0 +1,32 @@ +## daytona template create + +Create a workspace template + +``` +daytona template create [flags] +``` + +### Options + +``` + --builder BuildChoice Specify the builder (currently auto/devcontainer/none) + --custom-image string Create the workspace with the custom image passed as the flag value; Requires setting --custom-image-user flag as well + --custom-image-user string Create the workspace with the custom image user passed as the flag value; Requires setting --custom-image flag as well + --devcontainer-path string Automatically assign the devcontainer builder with the path passed as the flag value + --env stringArray Specify environment variables (e.g. --env 'KEY1=VALUE1' --env 'KEY2=VALUE2' ...') + --git-provider-config string Specify the Git provider configuration ID or alias + --label stringArray Specify labels (e.g. --label 'label.key1=VALUE1' --label 'label.key2=VALUE2' ...) + --manual Manually enter the Git repository + --name string Specify the workspace template name +``` + +### Options inherited from parent commands + +``` + --help help for daytona +``` + +### SEE ALSO + +* [daytona template](daytona_template.md) - Manage workspace templates + diff --git a/docs/daytona_project-config_delete.md b/docs/daytona_template_delete.md similarity index 50% rename from docs/daytona_project-config_delete.md rename to docs/daytona_template_delete.md index e235a32c80..c4559a3ee0 100644 --- a/docs/daytona_project-config_delete.md +++ b/docs/daytona_template_delete.md @@ -1,15 +1,15 @@ -## daytona project-config delete +## daytona template delete -Delete a project config +Delete a workspace template ``` -daytona project-config delete [flags] +daytona template delete [flags] ``` ### Options ``` - -a, --all Delete all project configs + -a, --all Delete all workspace templates -f, --force Force delete prebuild -y, --yes Confirm deletion without prompt ``` @@ -22,5 +22,5 @@ daytona project-config delete [flags] ### SEE ALSO -* [daytona project-config](daytona_project-config.md) - Manage project configs +* [daytona template](daytona_template.md) - Manage workspace templates diff --git a/docs/daytona_template_export.md b/docs/daytona_template_export.md new file mode 100644 index 0000000000..3ea35d78fe --- /dev/null +++ b/docs/daytona_template_export.md @@ -0,0 +1,25 @@ +## daytona template export + +Export a workspace template + +``` +daytona template export [flags] +``` + +### Options + +``` + -a, --all Export all workspace templates + -f, --format string Output format. Must be one of (yaml, json) +``` + +### Options inherited from parent commands + +``` + --help help for daytona +``` + +### SEE ALSO + +* [daytona template](daytona_template.md) - Manage workspace templates + diff --git a/docs/daytona_template_import.md b/docs/daytona_template_import.md new file mode 100644 index 0000000000..25a8a3d495 --- /dev/null +++ b/docs/daytona_template_import.md @@ -0,0 +1,24 @@ +## daytona template import + +Import a workspace template from a JSON object + +``` +daytona template import [flags] +``` + +### Options + +``` + -f, --file string Import workspace template from a JSON file. Use '-' to read from stdin. +``` + +### Options inherited from parent commands + +``` + --help help for daytona +``` + +### SEE ALSO + +* [daytona template](daytona_template.md) - Manage workspace templates + diff --git a/docs/daytona_project-config_info.md b/docs/daytona_template_info.md similarity index 53% rename from docs/daytona_project-config_info.md rename to docs/daytona_template_info.md index 4fca73851f..d1e74a373d 100644 --- a/docs/daytona_project-config_info.md +++ b/docs/daytona_template_info.md @@ -1,9 +1,9 @@ -## daytona project-config info +## daytona template info -Show project config info +Show workspace template info ``` -daytona project-config info [flags] +daytona template info [flags] ``` ### Options @@ -20,5 +20,5 @@ daytona project-config info [flags] ### SEE ALSO -* [daytona project-config](daytona_project-config.md) - Manage project configs +* [daytona template](daytona_template.md) - Manage workspace templates diff --git a/docs/daytona_template_list.md b/docs/daytona_template_list.md new file mode 100644 index 0000000000..d9516930f4 --- /dev/null +++ b/docs/daytona_template_list.md @@ -0,0 +1,24 @@ +## daytona template list + +Lists workspace templates + +``` +daytona template list [flags] +``` + +### Options + +``` + -f, --format string Output format. Must be one of (yaml, json) +``` + +### Options inherited from parent commands + +``` + --help help for daytona +``` + +### SEE ALSO + +* [daytona template](daytona_template.md) - Manage workspace templates + diff --git a/docs/daytona_template_set-default.md b/docs/daytona_template_set-default.md new file mode 100644 index 0000000000..42be561c23 --- /dev/null +++ b/docs/daytona_template_set-default.md @@ -0,0 +1,18 @@ +## daytona template set-default + +Set workspace template info + +``` +daytona template set-default [flags] +``` + +### Options inherited from parent commands + +``` + --help help for daytona +``` + +### SEE ALSO + +* [daytona template](daytona_template.md) - Manage workspace templates + diff --git a/docs/daytona_template_update.md b/docs/daytona_template_update.md new file mode 100644 index 0000000000..c6602fd52c --- /dev/null +++ b/docs/daytona_template_update.md @@ -0,0 +1,18 @@ +## daytona template update + +Update a workspace template + +``` +daytona template update [flags] +``` + +### Options inherited from parent commands + +``` + --help help for daytona +``` + +### SEE ALSO + +* [daytona template](daytona_template.md) - Manage workspace templates + diff --git a/docs/workspace_mode/daytona_logs.md b/docs/workspace_mode/daytona_logs.md deleted file mode 100644 index f8ea76bf48..0000000000 --- a/docs/workspace_mode/daytona_logs.md +++ /dev/null @@ -1,25 +0,0 @@ -## daytona logs - -View logs for a workspace/project - -``` -daytona logs [WORKSPACE] [PROJECT_NAME] [flags] -``` - -### Options - -``` - -f, --follow Follow logs - -w, --workspace View workspace logs -``` - -### Options inherited from parent commands - -``` - --help help for daytona -``` - -### SEE ALSO - -* [daytona](daytona.md) - Use the Daytona CLI to manage your workspace - diff --git a/docs/workspace_mode/daytona_restart.md b/docs/workspace_mode/daytona_restart.md deleted file mode 100644 index 3656356199..0000000000 --- a/docs/workspace_mode/daytona_restart.md +++ /dev/null @@ -1,18 +0,0 @@ -## daytona restart - -Restart the project - -``` -daytona restart [flags] -``` - -### Options inherited from parent commands - -``` - --help help for daytona -``` - -### SEE ALSO - -* [daytona](daytona.md) - Use the Daytona CLI to manage your workspace - diff --git a/docs/workspace_mode/daytona_start.md b/docs/workspace_mode/daytona_start.md deleted file mode 100644 index 9001876aa5..0000000000 --- a/docs/workspace_mode/daytona_start.md +++ /dev/null @@ -1,18 +0,0 @@ -## daytona start - -Start the project - -``` -daytona start [flags] -``` - -### Options inherited from parent commands - -``` - --help help for daytona -``` - -### SEE ALSO - -* [daytona](daytona.md) - Use the Daytona CLI to manage your workspace - diff --git a/docs/workspace_mode/daytona_stop.md b/docs/workspace_mode/daytona_stop.md deleted file mode 100644 index 10c858197d..0000000000 --- a/docs/workspace_mode/daytona_stop.md +++ /dev/null @@ -1,18 +0,0 @@ -## daytona stop - -Stop the project - -``` -daytona stop [flags] -``` - -### Options inherited from parent commands - -``` - --help help for daytona -``` - -### SEE ALSO - -* [daytona](daytona.md) - Use the Daytona CLI to manage your workspace - diff --git a/go.mod b/go.mod index fa397b18eb..d52446c12a 100644 --- a/go.mod +++ b/go.mod @@ -31,6 +31,7 @@ require ( github.com/go-git/go-git/v5 v5.12.1-0.20240617075238-c127d1b35535 github.com/go-playground/validator/v10 v10.19.0 github.com/go-playground/webhooks/v6 v6.4.0 + github.com/goccy/go-json v0.10.2 github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85 github.com/google/uuid v1.6.0 github.com/gorilla/websocket v1.5.1 @@ -149,7 +150,6 @@ require ( github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/go-viper/mapstructure/v2 v2.1.0 // indirect - github.com/goccy/go-json v0.10.2 // indirect github.com/godbus/dbus/v5 v5.1.1-0.20230522191255-76236955d466 // indirect github.com/gofrs/uuid/v5 v5.3.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect diff --git a/hack/builder_image/.devcontainer/devcontainer.json b/hack/builder_image/.devcontainer/devcontainer.json index 97d388e526..257d94f52a 100644 --- a/hack/builder_image/.devcontainer/devcontainer.json +++ b/hack/builder_image/.devcontainer/devcontainer.json @@ -1,5 +1,5 @@ { - "name": "Daytona Project Image Builder", + "name": "Daytona Workspace Image Builder", "image": "ubuntu:22.04", "features": { "ghcr.io/devcontainers/features/common-utils:1": { diff --git a/hack/docs/workspace_mode/daytona.yaml b/hack/docs/agent_mode/daytona.yaml similarity index 62% rename from hack/docs/workspace_mode/daytona.yaml rename to hack/docs/agent_mode/daytona.yaml index 6ebcdd6cb7..c44de9924c 100644 --- a/hack/docs/workspace_mode/daytona.yaml +++ b/hack/docs/agent_mode/daytona.yaml @@ -1,6 +1,6 @@ name: daytona -synopsis: Use the Daytona CLI to manage your workspace -description: Use the Daytona CLI to manage your workspace +synopsis: Daytona is a Dev Environment Manager +description: Daytona is a Dev Environment Manager usage: daytona [flags] options: - name: help @@ -14,12 +14,9 @@ see_also: - daytona agent - Start the agent process - daytona autocomplete - Adds a completion script for your shell environment - daytona docs - Opens the Daytona documentation in your default browser. - - daytona expose - Expose a local port over stdout - Used by the Daytona CLI to make direct connections to the project + - daytona expose - Expose a local port over stdout - Used by the Daytona CLI to make direct connections to the workspace - daytona forward - Forward a port publicly via an URL - - daytona info - Show project info + - daytona info - Show resource info - daytona list - List workspaces - - daytona logs - View logs for a workspace/project - - daytona restart - Restart the project - - daytona start - Start the project - - daytona stop - Stop the project + - daytona logs - View resource logs - daytona version - Print the version number diff --git a/hack/docs/workspace_mode/daytona_agent.yaml b/hack/docs/agent_mode/daytona_agent.yaml similarity index 70% rename from hack/docs/workspace_mode/daytona_agent.yaml rename to hack/docs/agent_mode/daytona_agent.yaml index 695c8062af..41ded210cb 100644 --- a/hack/docs/workspace_mode/daytona_agent.yaml +++ b/hack/docs/agent_mode/daytona_agent.yaml @@ -2,13 +2,13 @@ name: daytona agent synopsis: Start the agent process usage: daytona agent [flags] options: - - name: host + - name: target default_value: "false" - usage: Run the agent in host mode + usage: Run the agent in target mode inherited_options: - name: help default_value: "false" usage: help for daytona see_also: - - daytona - Use the Daytona CLI to manage your workspace + - daytona - Daytona is a Dev Environment Manager - daytona agent logs - Output Daytona Agent logs diff --git a/hack/docs/workspace_mode/daytona_agent_logs.yaml b/hack/docs/agent_mode/daytona_agent_logs.yaml similarity index 100% rename from hack/docs/workspace_mode/daytona_agent_logs.yaml rename to hack/docs/agent_mode/daytona_agent_logs.yaml diff --git a/hack/docs/workspace_mode/daytona_autocomplete.yaml b/hack/docs/agent_mode/daytona_autocomplete.yaml similarity index 80% rename from hack/docs/workspace_mode/daytona_autocomplete.yaml rename to hack/docs/agent_mode/daytona_autocomplete.yaml index e0efb0960c..3d7cd97846 100644 --- a/hack/docs/workspace_mode/daytona_autocomplete.yaml +++ b/hack/docs/agent_mode/daytona_autocomplete.yaml @@ -6,4 +6,4 @@ inherited_options: default_value: "false" usage: help for daytona see_also: - - daytona - Use the Daytona CLI to manage your workspace + - daytona - Daytona is a Dev Environment Manager diff --git a/hack/docs/workspace_mode/daytona_docs.yaml b/hack/docs/agent_mode/daytona_docs.yaml similarity index 78% rename from hack/docs/workspace_mode/daytona_docs.yaml rename to hack/docs/agent_mode/daytona_docs.yaml index 9e1a0a1a92..2eb2502768 100644 --- a/hack/docs/workspace_mode/daytona_docs.yaml +++ b/hack/docs/agent_mode/daytona_docs.yaml @@ -6,4 +6,4 @@ inherited_options: default_value: "false" usage: help for daytona see_also: - - daytona - Use the Daytona CLI to manage your workspace + - daytona - Daytona is a Dev Environment Manager diff --git a/hack/docs/workspace_mode/daytona_expose.yaml b/hack/docs/agent_mode/daytona_expose.yaml similarity index 70% rename from hack/docs/workspace_mode/daytona_expose.yaml rename to hack/docs/agent_mode/daytona_expose.yaml index ea5759cc4f..776659b284 100644 --- a/hack/docs/workspace_mode/daytona_expose.yaml +++ b/hack/docs/agent_mode/daytona_expose.yaml @@ -1,10 +1,10 @@ name: daytona expose synopsis: | - Expose a local port over stdout - Used by the Daytona CLI to make direct connections to the project + Expose a local port over stdout - Used by the Daytona CLI to make direct connections to the workspace usage: daytona expose [PORT] [flags] inherited_options: - name: help default_value: "false" usage: help for daytona see_also: - - daytona - Use the Daytona CLI to manage your workspace + - daytona - Daytona is a Dev Environment Manager diff --git a/hack/docs/workspace_mode/daytona_forward.yaml b/hack/docs/agent_mode/daytona_forward.yaml similarity index 77% rename from hack/docs/workspace_mode/daytona_forward.yaml rename to hack/docs/agent_mode/daytona_forward.yaml index dad403fea1..a6b70eea12 100644 --- a/hack/docs/workspace_mode/daytona_forward.yaml +++ b/hack/docs/agent_mode/daytona_forward.yaml @@ -6,4 +6,4 @@ inherited_options: default_value: "false" usage: help for daytona see_also: - - daytona - Use the Daytona CLI to manage your workspace + - daytona - Daytona is a Dev Environment Manager diff --git a/hack/docs/workspace_mode/daytona_info.yaml b/hack/docs/agent_mode/daytona_info.yaml similarity index 74% rename from hack/docs/workspace_mode/daytona_info.yaml rename to hack/docs/agent_mode/daytona_info.yaml index 68cdd2e178..8717176e9d 100644 --- a/hack/docs/workspace_mode/daytona_info.yaml +++ b/hack/docs/agent_mode/daytona_info.yaml @@ -1,5 +1,5 @@ name: daytona info -synopsis: Show project info +synopsis: Show resource info usage: daytona info [flags] options: - name: format @@ -10,4 +10,4 @@ inherited_options: default_value: "false" usage: help for daytona see_also: - - daytona - Use the Daytona CLI to manage your workspace + - daytona - Daytona is a Dev Environment Manager diff --git a/hack/docs/workspace_mode/daytona_list.yaml b/hack/docs/agent_mode/daytona_list.yaml similarity index 63% rename from hack/docs/workspace_mode/daytona_list.yaml rename to hack/docs/agent_mode/daytona_list.yaml index b55d1225f5..cc8b847664 100644 --- a/hack/docs/workspace_mode/daytona_list.yaml +++ b/hack/docs/agent_mode/daytona_list.yaml @@ -5,13 +5,13 @@ options: - name: format shorthand: f usage: Output format. Must be one of (yaml, json) - - name: verbose - shorthand: v - default_value: "false" - usage: Show verbose output + - name: label + shorthand: l + default_value: '[]' + usage: Filter by label inherited_options: - name: help default_value: "false" usage: help for daytona see_also: - - daytona - Use the Daytona CLI to manage your workspace + - daytona - Daytona is a Dev Environment Manager diff --git a/hack/docs/agent_mode/daytona_logs.yaml b/hack/docs/agent_mode/daytona_logs.yaml new file mode 100644 index 0000000000..b7eeb419a8 --- /dev/null +++ b/hack/docs/agent_mode/daytona_logs.yaml @@ -0,0 +1,9 @@ +name: daytona logs +synopsis: View resource logs +usage: daytona logs [flags] +inherited_options: + - name: help + default_value: "false" + usage: help for daytona +see_also: + - daytona - Daytona is a Dev Environment Manager diff --git a/hack/docs/workspace_mode/daytona_version.yaml b/hack/docs/agent_mode/daytona_version.yaml similarity index 75% rename from hack/docs/workspace_mode/daytona_version.yaml rename to hack/docs/agent_mode/daytona_version.yaml index 3557221589..02035a7170 100644 --- a/hack/docs/workspace_mode/daytona_version.yaml +++ b/hack/docs/agent_mode/daytona_version.yaml @@ -6,4 +6,4 @@ inherited_options: default_value: "false" usage: help for daytona see_also: - - daytona - Use the Daytona CLI to manage your workspace + - daytona - Daytona is a Dev Environment Manager diff --git a/hack/docs/daytona.yaml b/hack/docs/daytona.yaml index 611aba624e..c42e2a387d 100644 --- a/hack/docs/daytona.yaml +++ b/hack/docs/daytona.yaml @@ -16,30 +16,31 @@ see_also: - daytona build - Manage builds - daytona code - Open a workspace in your preferred IDE - daytona config - Output Daytona configuration - - daytona container-registry - Manage container registries - daytona create - Create a workspace - daytona delete - Delete a workspace - daytona docs - Opens the Daytona documentation in your default browser. - - daytona env - Manage profile environment variables that are added to all workspaces - - daytona forward - Forward a port from a project to your local machine - - daytona git-providers - Manage Git providers + - daytona env - Manage server environment variables that are added to all targets and workspaces + - daytona forward - Forward a port from a workspace to your local machine + - daytona git-provider - Manage Git provider configs - daytona ide - Choose the default IDE - daytona info - Show workspace info - daytona list - List workspaces - - daytona logs - View logs for a workspace/project + - daytona logs - View the logs of a workspace - daytona prebuild - Manage prebuilds - daytona profile - Manage profiles - - daytona project-config - Manage project configs - daytona provider - Manage providers - daytona purge - Purges all Daytona data from the current device - daytona restart - Restart a workspace + - daytona runner - Manage the runner - daytona serve - Run the server process in the current terminal session - daytona server - Start the server process in daemon mode - - daytona ssh - SSH into a project using the terminal + - daytona ssh - SSH into a workspace using the terminal - daytona start - Start a workspace - daytona stop - Stop a workspace - - daytona target - Manage provider targets + - daytona target - Manage targets + - daytona target-config - Manage target configs - daytona telemetry - Manage telemetry collection + - daytona template - Manage workspace templates - daytona update - Update Daytona CLI - daytona use - Use profile [PROFILE_NAME] - daytona version - Print the version number diff --git a/hack/docs/daytona_api-key.yaml b/hack/docs/daytona_api-key.yaml index a886de682c..828f053221 100644 --- a/hack/docs/daytona_api-key.yaml +++ b/hack/docs/daytona_api-key.yaml @@ -6,6 +6,6 @@ inherited_options: usage: help for daytona see_also: - daytona - Daytona is a Dev Environment Manager - - daytona api-key generate - Generate a new API key + - daytona api-key create - Create a new API key + - daytona api-key delete - Delete an API key - daytona api-key list - List API keys - - daytona api-key revoke - Revoke an API key diff --git a/hack/docs/daytona_api-key_generate.yaml b/hack/docs/daytona_api-key_create.yaml similarity index 56% rename from hack/docs/daytona_api-key_generate.yaml rename to hack/docs/daytona_api-key_create.yaml index 988087f62b..8851a68a79 100644 --- a/hack/docs/daytona_api-key_generate.yaml +++ b/hack/docs/daytona_api-key_create.yaml @@ -1,6 +1,6 @@ -name: daytona api-key generate -synopsis: Generate a new API key -usage: daytona api-key generate [NAME] [flags] +name: daytona api-key create +synopsis: Create a new API key +usage: daytona api-key create [NAME] [flags] inherited_options: - name: help default_value: "false" diff --git a/hack/docs/daytona_api-key_revoke.yaml b/hack/docs/daytona_api-key_delete.yaml similarity index 71% rename from hack/docs/daytona_api-key_revoke.yaml rename to hack/docs/daytona_api-key_delete.yaml index 2009ac9ee1..97c332363d 100644 --- a/hack/docs/daytona_api-key_revoke.yaml +++ b/hack/docs/daytona_api-key_delete.yaml @@ -1,6 +1,6 @@ -name: daytona api-key revoke -synopsis: Revoke an API key -usage: daytona api-key revoke [NAME] [flags] +name: daytona api-key delete +synopsis: Delete an API key +usage: daytona api-key delete [NAME] [flags] options: - name: "yes" shorthand: "y" diff --git a/hack/docs/daytona_build.yaml b/hack/docs/daytona_build.yaml index 555d40057f..eefad4b949 100644 --- a/hack/docs/daytona_build.yaml +++ b/hack/docs/daytona_build.yaml @@ -10,4 +10,4 @@ see_also: - daytona build info - Show build info - daytona build list - List all builds - daytona build logs - View logs for build - - daytona build run - Run a build from a project config + - daytona build run - Run a build from a workspace template diff --git a/hack/docs/daytona_build_run.yaml b/hack/docs/daytona_build_run.yaml index a0d2f7a6b0..ab0c7a394f 100644 --- a/hack/docs/daytona_build_run.yaml +++ b/hack/docs/daytona_build_run.yaml @@ -1,5 +1,5 @@ name: daytona build run -synopsis: Run a build from a project config +synopsis: Run a build from a workspace template usage: daytona build run [flags] inherited_options: - name: help diff --git a/hack/docs/daytona_code.yaml b/hack/docs/daytona_code.yaml index 049123a7d7..0af921605d 100644 --- a/hack/docs/daytona_code.yaml +++ b/hack/docs/daytona_code.yaml @@ -1,6 +1,6 @@ name: daytona code synopsis: Open a workspace in your preferred IDE -usage: daytona code [WORKSPACE] [PROJECT] [flags] +usage: daytona code [WORKSPACE] [flags] options: - name: ide shorthand: i diff --git a/hack/docs/daytona_container-registry.yaml b/hack/docs/daytona_container-registry.yaml deleted file mode 100644 index 8157d18d0d..0000000000 --- a/hack/docs/daytona_container-registry.yaml +++ /dev/null @@ -1,11 +0,0 @@ -name: daytona container-registry -synopsis: Manage container registries -inherited_options: - - name: help - default_value: "false" - usage: help for daytona -see_also: - - daytona - Daytona is a Dev Environment Manager - - daytona container-registry delete - Delete a container registry - - daytona container-registry list - Lists container registries - - daytona container-registry set - Set container registry diff --git a/hack/docs/daytona_container-registry_delete.yaml b/hack/docs/daytona_container-registry_delete.yaml deleted file mode 100644 index 8200c586fd..0000000000 --- a/hack/docs/daytona_container-registry_delete.yaml +++ /dev/null @@ -1,9 +0,0 @@ -name: daytona container-registry delete -synopsis: Delete a container registry -usage: daytona container-registry delete [flags] -inherited_options: - - name: help - default_value: "false" - usage: help for daytona -see_also: - - daytona container-registry - Manage container registries diff --git a/hack/docs/daytona_container-registry_list.yaml b/hack/docs/daytona_container-registry_list.yaml deleted file mode 100644 index be84cb144c..0000000000 --- a/hack/docs/daytona_container-registry_list.yaml +++ /dev/null @@ -1,13 +0,0 @@ -name: daytona container-registry list -synopsis: Lists container registries -usage: daytona container-registry list [flags] -options: - - name: format - shorthand: f - usage: Output format. Must be one of (yaml, json) -inherited_options: - - name: help - default_value: "false" - usage: help for daytona -see_also: - - daytona container-registry - Manage container registries diff --git a/hack/docs/daytona_container-registry_set.yaml b/hack/docs/daytona_container-registry_set.yaml deleted file mode 100644 index b4ca3426b9..0000000000 --- a/hack/docs/daytona_container-registry_set.yaml +++ /dev/null @@ -1,19 +0,0 @@ -name: daytona container-registry set -synopsis: Set container registry -usage: daytona container-registry set [flags] -options: - - name: password - shorthand: p - usage: Password - - name: server - shorthand: s - usage: Server - - name: username - shorthand: u - usage: Username -inherited_options: - - name: help - default_value: "false" - usage: help for daytona -see_also: - - daytona container-registry - Manage container registries diff --git a/hack/docs/daytona_create.yaml b/hack/docs/daytona_create.yaml index d8afd7b6ab..4d3161bcac 100644 --- a/hack/docs/daytona_create.yaml +++ b/hack/docs/daytona_create.yaml @@ -1,21 +1,21 @@ name: daytona create synopsis: Create a workspace -usage: daytona create [REPOSITORY_URL | PROJECT_CONFIG_NAME]... [flags] +usage: daytona create [REPOSITORY_URL | WORKSPACE_CONFIG_NAME]... [flags] options: - name: blank default_value: "false" - usage: Create a blank project without using existing configurations + usage: Create a blank workspace without using existing templates - name: branch default_value: '[]' - usage: Specify the Git branches to use in the projects + usage: Specify the Git branches to use in the workspaces - name: builder usage: Specify the builder (currently auto/devcontainer/none) - name: custom-image usage: | - Create the project with the custom image passed as the flag value; Requires setting --custom-image-user flag as well + Create the workspace with the custom image passed as the flag value; Requires setting --custom-image-user flag as well - name: custom-image-user usage: | - Create the project with the custom image user passed as the flag value; Requires setting --custom-image flag as well + Create the workspace with the custom image user passed as the flag value; Requires setting --custom-image flag as well - name: devcontainer-path usage: | Automatically assign the devcontainer builder with the path passed as the flag value @@ -29,19 +29,20 @@ options: shorthand: i usage: | Specify the IDE (vscode, code-insiders, browser, cursor, codium, codium-insiders, ssh, jupyter, fleet, positron, zed, windsurf, clion, goland, intellij, phpstorm, pycharm, rider, rubymine, webstorm) + - name: label + default_value: '[]' + usage: | + Specify labels (e.g. --label 'label.key1=VALUE1' --label 'label.key2=VALUE2' ...) - name: manual default_value: "false" usage: Manually enter the Git repository - - name: multi-project + - name: multi-workspace default_value: "false" - usage: Workspace with multiple projects/repos - - name: name - usage: Specify the workspace name + usage: Target with multiple workspaces/repos - name: no-ide shorthand: "n" default_value: "false" - usage: | - Do not open the workspace in the IDE after workspace creation + usage: Do not open the target in the IDE after target creation - name: target shorthand: t usage: Specify the target (e.g. 'local') diff --git a/hack/docs/daytona_delete.yaml b/hack/docs/daytona_delete.yaml index f7e3545122..96a5c8d97b 100644 --- a/hack/docs/daytona_delete.yaml +++ b/hack/docs/daytona_delete.yaml @@ -1,6 +1,6 @@ name: daytona delete synopsis: Delete a workspace -usage: daytona delete [WORKSPACE] [flags] +usage: daytona delete [WORKSPACE]... [flags] options: - name: all shorthand: a diff --git a/hack/docs/daytona_env.yaml b/hack/docs/daytona_env.yaml index 8b53a3511c..60e8d4172c 100644 --- a/hack/docs/daytona_env.yaml +++ b/hack/docs/daytona_env.yaml @@ -1,11 +1,12 @@ name: daytona env synopsis: | - Manage profile environment variables that are added to all workspaces + Manage server environment variables that are added to all targets and workspaces inherited_options: - name: help default_value: "false" usage: help for daytona see_also: - daytona - Daytona is a Dev Environment Manager - - daytona env list - List profile environment variables - - daytona env set - Set profile environment variables + - daytona env delete - Delete server environment variables + - daytona env list - List server environment variables + - daytona env set - Set server environment variables diff --git a/hack/docs/daytona_env_delete.yaml b/hack/docs/daytona_env_delete.yaml new file mode 100644 index 0000000000..b5f703bc42 --- /dev/null +++ b/hack/docs/daytona_env_delete.yaml @@ -0,0 +1,9 @@ +name: daytona env delete +synopsis: Delete server environment variables +usage: daytona env delete [KEY]... [flags] +inherited_options: + - name: help + default_value: "false" + usage: help for daytona +see_also: + - daytona env - Manage server environment variables that are added to all targets and workspaces diff --git a/hack/docs/daytona_env_list.yaml b/hack/docs/daytona_env_list.yaml index a199339142..da0588f306 100644 --- a/hack/docs/daytona_env_list.yaml +++ b/hack/docs/daytona_env_list.yaml @@ -1,13 +1,17 @@ name: daytona env list -synopsis: List profile environment variables +synopsis: List server environment variables usage: daytona env list [flags] options: - name: format shorthand: f usage: Output format. Must be one of (yaml, json) + - name: show-values + shorthand: v + default_value: "false" + usage: Show environment variable values inherited_options: - name: help default_value: "false" usage: help for daytona see_also: - - daytona env - Manage profile environment variables that are added to all workspaces + - daytona env - Manage server environment variables that are added to all targets and workspaces diff --git a/hack/docs/daytona_env_set.yaml b/hack/docs/daytona_env_set.yaml index de033d3165..2dd1cb0ccb 100644 --- a/hack/docs/daytona_env_set.yaml +++ b/hack/docs/daytona_env_set.yaml @@ -1,9 +1,9 @@ name: daytona env set -synopsis: Set profile environment variables +synopsis: Set server environment variables usage: daytona env set [KEY=VALUE]... [flags] inherited_options: - name: help default_value: "false" usage: help for daytona see_also: - - daytona env - Manage profile environment variables that are added to all workspaces + - daytona env - Manage server environment variables that are added to all targets and workspaces diff --git a/hack/docs/daytona_forward.yaml b/hack/docs/daytona_forward.yaml index 2b1e418dea..2e0a52361d 100644 --- a/hack/docs/daytona_forward.yaml +++ b/hack/docs/daytona_forward.yaml @@ -1,6 +1,6 @@ name: daytona forward -synopsis: Forward a port from a project to your local machine -usage: daytona forward [PORT] [WORKSPACE] [PROJECT] [flags] +synopsis: Forward a port from a workspace to your local machine +usage: daytona forward [PORT] [WORKSPACE] [flags] options: - name: public default_value: "false" diff --git a/hack/docs/daytona_git-provider.yaml b/hack/docs/daytona_git-provider.yaml new file mode 100644 index 0000000000..4e56d440ee --- /dev/null +++ b/hack/docs/daytona_git-provider.yaml @@ -0,0 +1,12 @@ +name: daytona git-provider +synopsis: Manage Git provider configs +inherited_options: + - name: help + default_value: "false" + usage: help for daytona +see_also: + - daytona - Daytona is a Dev Environment Manager + - daytona git-provider create - Create a Git provider config + - daytona git-provider delete - Delete a Git provider config + - daytona git-provider list - Lists your registered Git provider configs + - daytona git-provider update - Update a Git provider diff --git a/hack/docs/daytona_git-providers_add.yaml b/hack/docs/daytona_git-provider_create.yaml similarity index 73% rename from hack/docs/daytona_git-providers_add.yaml rename to hack/docs/daytona_git-provider_create.yaml index 30b5b7f50c..38d30879f1 100644 --- a/hack/docs/daytona_git-providers_add.yaml +++ b/hack/docs/daytona_git-provider_create.yaml @@ -1,6 +1,6 @@ -name: daytona git-providers add -synopsis: Register a Git provider -usage: daytona git-providers add [GIT_PROVIDER_ID] [flags] +name: daytona git-provider create +synopsis: Create a Git provider config +usage: daytona git-provider create [GIT_PROVIDER_ID] [flags] options: - name: alias shorthand: a @@ -25,4 +25,4 @@ inherited_options: default_value: "false" usage: help for daytona see_also: - - daytona git-providers - Manage Git providers + - daytona git-provider - Manage Git provider configs diff --git a/hack/docs/daytona_git-providers_delete.yaml b/hack/docs/daytona_git-provider_delete.yaml similarity index 57% rename from hack/docs/daytona_git-providers_delete.yaml rename to hack/docs/daytona_git-provider_delete.yaml index 95d0109933..c02f62b381 100644 --- a/hack/docs/daytona_git-providers_delete.yaml +++ b/hack/docs/daytona_git-provider_delete.yaml @@ -1,11 +1,11 @@ -name: daytona git-providers delete -synopsis: Unregister a Git provider -usage: daytona git-providers delete [flags] +name: daytona git-provider delete +synopsis: Delete a Git provider config +usage: daytona git-provider delete [flags] options: - name: all shorthand: a default_value: "false" - usage: Remove all Git providers + usage: Delete all Git providers - name: "yes" shorthand: "y" default_value: "false" @@ -15,4 +15,4 @@ inherited_options: default_value: "false" usage: help for daytona see_also: - - daytona git-providers - Manage Git providers + - daytona git-provider - Manage Git provider configs diff --git a/hack/docs/daytona_git-provider_list.yaml b/hack/docs/daytona_git-provider_list.yaml new file mode 100644 index 0000000000..1d28e5028c --- /dev/null +++ b/hack/docs/daytona_git-provider_list.yaml @@ -0,0 +1,13 @@ +name: daytona git-provider list +synopsis: Lists your registered Git provider configs +usage: daytona git-provider list [flags] +options: + - name: format + shorthand: f + usage: Output format. Must be one of (yaml, json) +inherited_options: + - name: help + default_value: "false" + usage: help for daytona +see_also: + - daytona git-provider - Manage Git provider configs diff --git a/hack/docs/daytona_git-providers_update.yaml b/hack/docs/daytona_git-provider_update.yaml similarity index 50% rename from hack/docs/daytona_git-providers_update.yaml rename to hack/docs/daytona_git-provider_update.yaml index 3782e8afda..afb8879df3 100644 --- a/hack/docs/daytona_git-providers_update.yaml +++ b/hack/docs/daytona_git-provider_update.yaml @@ -1,9 +1,9 @@ -name: daytona git-providers update +name: daytona git-provider update synopsis: Update a Git provider -usage: daytona git-providers update [flags] +usage: daytona git-provider update [flags] inherited_options: - name: help default_value: "false" usage: help for daytona see_also: - - daytona git-providers - Manage Git providers + - daytona git-provider - Manage Git provider configs diff --git a/hack/docs/daytona_git-providers.yaml b/hack/docs/daytona_git-providers.yaml deleted file mode 100644 index 0d80b38486..0000000000 --- a/hack/docs/daytona_git-providers.yaml +++ /dev/null @@ -1,12 +0,0 @@ -name: daytona git-providers -synopsis: Manage Git providers -inherited_options: - - name: help - default_value: "false" - usage: help for daytona -see_also: - - daytona - Daytona is a Dev Environment Manager - - daytona git-providers add - Register a Git provider - - daytona git-providers delete - Unregister a Git provider - - daytona git-providers list - Lists your registered Git providers - - daytona git-providers update - Update a Git provider diff --git a/hack/docs/daytona_list.yaml b/hack/docs/daytona_list.yaml index e4efaaea82..cc8b847664 100644 --- a/hack/docs/daytona_list.yaml +++ b/hack/docs/daytona_list.yaml @@ -5,10 +5,10 @@ options: - name: format shorthand: f usage: Output format. Must be one of (yaml, json) - - name: verbose - shorthand: v - default_value: "false" - usage: Show verbose output + - name: label + shorthand: l + default_value: '[]' + usage: Filter by label inherited_options: - name: help default_value: "false" diff --git a/hack/docs/daytona_logs.yaml b/hack/docs/daytona_logs.yaml index 2394b7e87a..d3d06469a3 100644 --- a/hack/docs/daytona_logs.yaml +++ b/hack/docs/daytona_logs.yaml @@ -1,15 +1,11 @@ name: daytona logs -synopsis: View logs for a workspace/project -usage: daytona logs [WORKSPACE] [PROJECT_NAME] [flags] +synopsis: View the logs of a workspace +usage: daytona logs [WORKSPACE] [flags] options: - name: follow shorthand: f default_value: "false" usage: Follow logs - - name: workspace - shorthand: w - default_value: "false" - usage: View workspace logs inherited_options: - name: help default_value: "false" diff --git a/hack/docs/daytona_prebuild.yaml b/hack/docs/daytona_prebuild.yaml index d667986aa0..815be39a0c 100644 --- a/hack/docs/daytona_prebuild.yaml +++ b/hack/docs/daytona_prebuild.yaml @@ -6,7 +6,7 @@ inherited_options: usage: help for daytona see_also: - daytona - Daytona is a Dev Environment Manager - - daytona prebuild add - Add a prebuild configuration + - daytona prebuild create - Create a prebuild configuration - daytona prebuild delete - Delete a prebuild configuration - daytona prebuild info - Show prebuild configuration info - daytona prebuild list - List prebuild configurations diff --git a/hack/docs/daytona_prebuild_add.yaml b/hack/docs/daytona_prebuild_create.yaml similarity index 85% rename from hack/docs/daytona_prebuild_add.yaml rename to hack/docs/daytona_prebuild_create.yaml index c448c05dd4..0e985f0a62 100644 --- a/hack/docs/daytona_prebuild_add.yaml +++ b/hack/docs/daytona_prebuild_create.yaml @@ -1,6 +1,6 @@ -name: daytona prebuild add -synopsis: Add a prebuild configuration -usage: daytona prebuild add [PROJECT_CONFIG] [flags] +name: daytona prebuild create +synopsis: Create a prebuild configuration +usage: daytona prebuild create [WORKSPACE_CONFIG] [flags] options: - name: branch shorthand: b diff --git a/hack/docs/daytona_prebuild_delete.yaml b/hack/docs/daytona_prebuild_delete.yaml index 0deb02f7cb..c2f21435e3 100644 --- a/hack/docs/daytona_prebuild_delete.yaml +++ b/hack/docs/daytona_prebuild_delete.yaml @@ -1,6 +1,6 @@ name: daytona prebuild delete synopsis: Delete a prebuild configuration -usage: daytona prebuild delete [PROJECT_CONFIG] [PREBUILD] [flags] +usage: daytona prebuild delete [WORKSPACE_CONFIG] [PREBUILD] [flags] options: - name: force shorthand: f diff --git a/hack/docs/daytona_prebuild_update.yaml b/hack/docs/daytona_prebuild_update.yaml index 4454b4b2f5..d6081e097f 100644 --- a/hack/docs/daytona_prebuild_update.yaml +++ b/hack/docs/daytona_prebuild_update.yaml @@ -1,6 +1,6 @@ name: daytona prebuild update synopsis: Update a prebuild configuration -usage: daytona prebuild update [PROJECT_CONFIG] [PREBUILD_ID] [flags] +usage: daytona prebuild update [WORKSPACE_CONFIG] [PREBUILD_ID] [flags] options: - name: branch shorthand: b diff --git a/hack/docs/daytona_profile.yaml b/hack/docs/daytona_profile.yaml index a9cc38d245..1a8c47f964 100644 --- a/hack/docs/daytona_profile.yaml +++ b/hack/docs/daytona_profile.yaml @@ -6,8 +6,8 @@ inherited_options: usage: help for daytona see_also: - daytona - Daytona is a Dev Environment Manager - - daytona profile add - Add profile - - daytona profile delete - Delete profile [PROFILE_NAME] - - daytona profile edit - Edit profile [PROFILE_NAME] + - daytona profile create - Create a profile + - daytona profile delete - Delete a profile - daytona profile list - List profiles + - daytona profile update - Update profile [PROFILE_NAME] - daytona use - Use profile [PROFILE_NAME] diff --git a/hack/docs/daytona_profile_add.yaml b/hack/docs/daytona_profile_create.yaml similarity index 78% rename from hack/docs/daytona_profile_add.yaml rename to hack/docs/daytona_profile_create.yaml index c2c08730a2..e803f67969 100644 --- a/hack/docs/daytona_profile_add.yaml +++ b/hack/docs/daytona_profile_create.yaml @@ -1,6 +1,6 @@ -name: daytona profile add -synopsis: Add profile -usage: daytona profile add [flags] +name: daytona profile create +synopsis: Create a profile +usage: daytona profile create [flags] options: - name: api-key shorthand: k diff --git a/hack/docs/daytona_profile_delete.yaml b/hack/docs/daytona_profile_delete.yaml index 95628ac7c8..4041504d23 100644 --- a/hack/docs/daytona_profile_delete.yaml +++ b/hack/docs/daytona_profile_delete.yaml @@ -1,6 +1,6 @@ name: daytona profile delete -synopsis: Delete profile [PROFILE_NAME] -usage: daytona profile delete [flags] +synopsis: Delete a profile +usage: daytona profile delete [PROFILE_NAME] [flags] inherited_options: - name: help default_value: "false" diff --git a/hack/docs/daytona_profile_edit.yaml b/hack/docs/daytona_profile_update.yaml similarity index 75% rename from hack/docs/daytona_profile_edit.yaml rename to hack/docs/daytona_profile_update.yaml index a2c71353d6..d299da83aa 100644 --- a/hack/docs/daytona_profile_edit.yaml +++ b/hack/docs/daytona_profile_update.yaml @@ -1,6 +1,6 @@ -name: daytona profile edit -synopsis: Edit profile [PROFILE_NAME] -usage: daytona profile edit [flags] +name: daytona profile update +synopsis: Update profile [PROFILE_NAME] +usage: daytona profile update [flags] options: - name: api-key shorthand: k diff --git a/hack/docs/daytona_project-config.yaml b/hack/docs/daytona_project-config.yaml deleted file mode 100644 index bd3a0c9c0f..0000000000 --- a/hack/docs/daytona_project-config.yaml +++ /dev/null @@ -1,16 +0,0 @@ -name: daytona project-config -synopsis: Manage project configs -inherited_options: - - name: help - default_value: "false" - usage: help for daytona -see_also: - - daytona - Daytona is a Dev Environment Manager - - daytona project-config add - Add a project config - - daytona project-config delete - Delete a project config - - daytona project-config export - Export a project config - - daytona project-config import - Import project config from JSON - - daytona project-config info - Show project config info - - daytona project-config list - Lists project configs - - daytona project-config set-default - Set project config info - - daytona project-config update - Update a project config diff --git a/hack/docs/daytona_project-config_import.yaml b/hack/docs/daytona_project-config_import.yaml deleted file mode 100644 index 21218881dd..0000000000 --- a/hack/docs/daytona_project-config_import.yaml +++ /dev/null @@ -1,14 +0,0 @@ -name: daytona project-config import -synopsis: Import project config from JSON -usage: daytona project-config import [flags] -options: - - name: file - shorthand: f - usage: | - Import project config from a JSON file. Use '-' to read from stdin. -inherited_options: - - name: help - default_value: "false" - usage: help for daytona -see_also: - - daytona project-config - Manage project configs diff --git a/hack/docs/daytona_project-config_set-default.yaml b/hack/docs/daytona_project-config_set-default.yaml deleted file mode 100644 index bbbf42c4c6..0000000000 --- a/hack/docs/daytona_project-config_set-default.yaml +++ /dev/null @@ -1,9 +0,0 @@ -name: daytona project-config set-default -synopsis: Set project config info -usage: daytona project-config set-default [flags] -inherited_options: - - name: help - default_value: "false" - usage: help for daytona -see_also: - - daytona project-config - Manage project configs diff --git a/hack/docs/daytona_project-config_update.yaml b/hack/docs/daytona_project-config_update.yaml deleted file mode 100644 index 2de5a2aa47..0000000000 --- a/hack/docs/daytona_project-config_update.yaml +++ /dev/null @@ -1,9 +0,0 @@ -name: daytona project-config update -synopsis: Update a project config -usage: daytona project-config update [flags] -inherited_options: - - name: help - default_value: "false" - usage: help for daytona -see_also: - - daytona project-config - Manage project configs diff --git a/hack/docs/daytona_purge.yaml b/hack/docs/daytona_purge.yaml index d79b020079..73d34c8aa5 100644 --- a/hack/docs/daytona_purge.yaml +++ b/hack/docs/daytona_purge.yaml @@ -1,17 +1,17 @@ name: daytona purge synopsis: Purges all Daytona data from the current device description: | - Purges all Daytona data from the current device - including all workspaces, configuration files, and SSH files. This command is irreversible. + Purges all Daytona data from the current device - including all local runner providers, configuration files and SSH files. This command is irreversible. usage: daytona purge [flags] options: - name: force shorthand: f default_value: "false" - usage: Delete all workspaces by force + usage: Delete all targets by force - name: "yes" shorthand: "y" default_value: "false" - usage: Execute purge without prompt + usage: Execute purge without a prompt inherited_options: - name: help default_value: "false" diff --git a/hack/docs/daytona_restart.yaml b/hack/docs/daytona_restart.yaml index 264482dfd8..d2b1eb9724 100644 --- a/hack/docs/daytona_restart.yaml +++ b/hack/docs/daytona_restart.yaml @@ -1,10 +1,6 @@ name: daytona restart synopsis: Restart a workspace -usage: daytona restart [WORKSPACE] [flags] -options: - - name: project - shorthand: p - usage: Restart a single project in the workspace (project name) +usage: daytona restart [WORKSPACE]... [flags] inherited_options: - name: help default_value: "false" diff --git a/hack/docs/daytona_runner.yaml b/hack/docs/daytona_runner.yaml new file mode 100644 index 0000000000..eeeda1e074 --- /dev/null +++ b/hack/docs/daytona_runner.yaml @@ -0,0 +1,16 @@ +name: daytona runner +synopsis: Manage the runner +inherited_options: + - name: help + default_value: "false" + usage: help for daytona +see_also: + - daytona - Daytona is a Dev Environment Manager + - daytona runner config - Outputs Daytona Runner config + - daytona runner configure - Configure Daytona Runner + - daytona runner logs - View runner logs + - daytona runner purge - Purges the Daytona Runner + - daytona runner restart - Restarts the runner + - daytona runner serve - Starts the runner in the foreground + - daytona runner start - Starts the runner + - daytona runner stop - Stops the runner diff --git a/hack/docs/daytona_runner_config.yaml b/hack/docs/daytona_runner_config.yaml new file mode 100644 index 0000000000..b417336250 --- /dev/null +++ b/hack/docs/daytona_runner_config.yaml @@ -0,0 +1,17 @@ +name: daytona runner config +synopsis: Outputs Daytona Runner config +usage: daytona runner config [flags] +options: + - name: format + shorthand: f + usage: Output format. Must be one of (yaml, json) + - name: key + shorthand: k + default_value: "false" + usage: Show API Key +inherited_options: + - name: help + default_value: "false" + usage: help for daytona +see_also: + - daytona runner - Manage the runner diff --git a/hack/docs/daytona_runner_configure.yaml b/hack/docs/daytona_runner_configure.yaml new file mode 100644 index 0000000000..d2bbdaedb6 --- /dev/null +++ b/hack/docs/daytona_runner_configure.yaml @@ -0,0 +1,23 @@ +name: daytona runner configure +synopsis: Configure Daytona Runner +usage: daytona runner configure [flags] +options: + - name: api-key + usage: Runner API Key + - name: api-url + usage: Daytona Server API URL + - name: client-id + usage: Client ID + - name: disable-telemetry + default_value: "false" + usage: Disable telemetry + - name: id + usage: Runner ID + - name: name + usage: Runner Name +inherited_options: + - name: help + default_value: "false" + usage: help for daytona +see_also: + - daytona runner - Manage the runner diff --git a/hack/docs/daytona_runner_logs.yaml b/hack/docs/daytona_runner_logs.yaml new file mode 100644 index 0000000000..69e7d65072 --- /dev/null +++ b/hack/docs/daytona_runner_logs.yaml @@ -0,0 +1,14 @@ +name: daytona runner logs +synopsis: View runner logs +usage: daytona runner logs [flags] +options: + - name: follow + shorthand: f + default_value: "false" + usage: Follow logs +inherited_options: + - name: help + default_value: "false" + usage: help for daytona +see_also: + - daytona runner - Manage the runner diff --git a/hack/docs/daytona_runner_purge.yaml b/hack/docs/daytona_runner_purge.yaml new file mode 100644 index 0000000000..d5c53af30e --- /dev/null +++ b/hack/docs/daytona_runner_purge.yaml @@ -0,0 +1,14 @@ +name: daytona runner purge +synopsis: Purges the Daytona Runner +usage: daytona runner purge [flags] +options: + - name: "yes" + shorthand: "y" + default_value: "false" + usage: Execute Daytona Runner purge without a prompt +inherited_options: + - name: help + default_value: "false" + usage: help for daytona +see_also: + - daytona runner - Manage the runner diff --git a/hack/docs/daytona_runner_restart.yaml b/hack/docs/daytona_runner_restart.yaml new file mode 100644 index 0000000000..b788c67085 --- /dev/null +++ b/hack/docs/daytona_runner_restart.yaml @@ -0,0 +1,9 @@ +name: daytona runner restart +synopsis: Restarts the runner +usage: daytona runner restart [flags] +inherited_options: + - name: help + default_value: "false" + usage: help for daytona +see_also: + - daytona runner - Manage the runner diff --git a/hack/docs/daytona_runner_serve.yaml b/hack/docs/daytona_runner_serve.yaml new file mode 100644 index 0000000000..8f2bc20ada --- /dev/null +++ b/hack/docs/daytona_runner_serve.yaml @@ -0,0 +1,9 @@ +name: daytona runner serve +synopsis: Starts the runner in the foreground +usage: daytona runner serve [flags] +inherited_options: + - name: help + default_value: "false" + usage: help for daytona +see_also: + - daytona runner - Manage the runner diff --git a/hack/docs/daytona_runner_start.yaml b/hack/docs/daytona_runner_start.yaml new file mode 100644 index 0000000000..6ada5f90d1 --- /dev/null +++ b/hack/docs/daytona_runner_start.yaml @@ -0,0 +1,9 @@ +name: daytona runner start +synopsis: Starts the runner +usage: daytona runner start [flags] +inherited_options: + - name: help + default_value: "false" + usage: help for daytona +see_also: + - daytona runner - Manage the runner diff --git a/hack/docs/daytona_runner_stop.yaml b/hack/docs/daytona_runner_stop.yaml new file mode 100644 index 0000000000..d8e0d3fed8 --- /dev/null +++ b/hack/docs/daytona_runner_stop.yaml @@ -0,0 +1,9 @@ +name: daytona runner stop +synopsis: Stops the runner +usage: daytona runner stop [flags] +inherited_options: + - name: help + default_value: "false" + usage: help for daytona +see_also: + - daytona runner - Manage the runner diff --git a/hack/docs/daytona_server.yaml b/hack/docs/daytona_server.yaml index 6f19f3150f..a0fa4433c4 100644 --- a/hack/docs/daytona_server.yaml +++ b/hack/docs/daytona_server.yaml @@ -16,5 +16,6 @@ see_also: - daytona server configure - Configure Daytona Server - daytona server logs - Output Daytona Server logs - daytona server restart - Restarts the Daytona Server daemon + - daytona server runner - Manage runners - daytona server start - Start the Daytona Server daemon - daytona server stop - Stops the Daytona Server daemon diff --git a/hack/docs/daytona_server_runner.yaml b/hack/docs/daytona_server_runner.yaml new file mode 100644 index 0000000000..60e87707f7 --- /dev/null +++ b/hack/docs/daytona_server_runner.yaml @@ -0,0 +1,12 @@ +name: daytona server runner +synopsis: Manage runners +inherited_options: + - name: help + default_value: "false" + usage: help for daytona +see_also: + - daytona server - Start the server process in daemon mode + - daytona server runner create - Create a runner + - daytona server runner delete - Delete a runner + - daytona server runner list - List runners + - daytona server runner logs - View runner logs diff --git a/hack/docs/daytona_server_runner_create.yaml b/hack/docs/daytona_server_runner_create.yaml new file mode 100644 index 0000000000..5cb76176a2 --- /dev/null +++ b/hack/docs/daytona_server_runner_create.yaml @@ -0,0 +1,13 @@ +name: daytona server runner create +synopsis: Create a runner +usage: daytona server runner create [flags] +options: + - name: name + shorthand: "n" + usage: Runner name +inherited_options: + - name: help + default_value: "false" + usage: help for daytona +see_also: + - daytona server runner - Manage runners diff --git a/hack/docs/daytona_server_runner_delete.yaml b/hack/docs/daytona_server_runner_delete.yaml new file mode 100644 index 0000000000..39a5ccb875 --- /dev/null +++ b/hack/docs/daytona_server_runner_delete.yaml @@ -0,0 +1,14 @@ +name: daytona server runner delete +synopsis: Delete a runner +usage: daytona server runner delete [RUNNER] [flags] +options: + - name: "yes" + shorthand: "y" + default_value: "false" + usage: Confirm deletion without prompt +inherited_options: + - name: help + default_value: "false" + usage: help for daytona +see_also: + - daytona server runner - Manage runners diff --git a/hack/docs/daytona_project-config_list.yaml b/hack/docs/daytona_server_runner_list.yaml similarity index 56% rename from hack/docs/daytona_project-config_list.yaml rename to hack/docs/daytona_server_runner_list.yaml index 7deac6e153..ee0dcf3d08 100644 --- a/hack/docs/daytona_project-config_list.yaml +++ b/hack/docs/daytona_server_runner_list.yaml @@ -1,6 +1,6 @@ -name: daytona project-config list -synopsis: Lists project configs -usage: daytona project-config list [flags] +name: daytona server runner list +synopsis: List runners +usage: daytona server runner list [flags] options: - name: format shorthand: f @@ -10,4 +10,4 @@ inherited_options: default_value: "false" usage: help for daytona see_also: - - daytona project-config - Manage project configs + - daytona server runner - Manage runners diff --git a/hack/docs/daytona_server_runner_logs.yaml b/hack/docs/daytona_server_runner_logs.yaml new file mode 100644 index 0000000000..78f53a7db6 --- /dev/null +++ b/hack/docs/daytona_server_runner_logs.yaml @@ -0,0 +1,14 @@ +name: daytona server runner logs +synopsis: View runner logs +usage: daytona server runner logs [RUNNER_ID] [flags] +options: + - name: follow + shorthand: f + default_value: "false" + usage: Follow logs +inherited_options: + - name: help + default_value: "false" + usage: help for daytona +see_also: + - daytona server runner - Manage runners diff --git a/hack/docs/daytona_ssh.yaml b/hack/docs/daytona_ssh.yaml index 7bee33b3b5..4b7e7b2513 100644 --- a/hack/docs/daytona_ssh.yaml +++ b/hack/docs/daytona_ssh.yaml @@ -1,11 +1,11 @@ name: daytona ssh -synopsis: SSH into a project using the terminal -usage: daytona ssh [WORKSPACE] [PROJECT] [CMD...] [flags] +synopsis: SSH into a workspace using the terminal +usage: daytona ssh [WORKSPACE] [CMD...] [flags] options: - name: edit shorthand: e default_value: "false" - usage: Edit the project's SSH config + usage: Edit the workspace's SSH config - name: option shorthand: o default_value: '[]' diff --git a/hack/docs/daytona_start.yaml b/hack/docs/daytona_start.yaml index 67321ae0b9..1c4e966446 100644 --- a/hack/docs/daytona_start.yaml +++ b/hack/docs/daytona_start.yaml @@ -1,18 +1,15 @@ name: daytona start synopsis: Start a workspace -usage: daytona start [WORKSPACE] [flags] +usage: daytona start [WORKSPACE]... [flags] options: - name: all shorthand: a default_value: "false" - usage: Start all workspaces + usage: Start all targets - name: code shorthand: c default_value: "false" - usage: Open the workspace in the IDE after workspace start - - name: project - shorthand: p - usage: Start a single project in the workspace (project name) + usage: Open the target in the IDE after target start - name: "yes" shorthand: "y" default_value: "false" diff --git a/hack/docs/daytona_stop.yaml b/hack/docs/daytona_stop.yaml index e257217fd5..1d63c27376 100644 --- a/hack/docs/daytona_stop.yaml +++ b/hack/docs/daytona_stop.yaml @@ -1,14 +1,15 @@ name: daytona stop synopsis: Stop a workspace -usage: daytona stop [WORKSPACE] [flags] +usage: daytona stop [WORKSPACE]... [flags] options: - name: all shorthand: a default_value: "false" - usage: Stop all workspaces - - name: project - shorthand: p - usage: Stop a single project in the workspace (project name) + usage: Stop all targets + - name: "yes" + shorthand: "y" + default_value: "false" + usage: Automatically confirm any prompts inherited_options: - name: help default_value: "false" diff --git a/hack/docs/daytona_target-config.yaml b/hack/docs/daytona_target-config.yaml new file mode 100644 index 0000000000..92a38a5fe9 --- /dev/null +++ b/hack/docs/daytona_target-config.yaml @@ -0,0 +1,11 @@ +name: daytona target-config +synopsis: Manage target configs +inherited_options: + - name: help + default_value: "false" + usage: help for daytona +see_also: + - daytona - Daytona is a Dev Environment Manager + - daytona target-config create - Create target config + - daytona target-config delete - Deletes a target config + - daytona target-config list - List target configs diff --git a/hack/docs/daytona_target_set.yaml b/hack/docs/daytona_target-config_create.yaml similarity index 60% rename from hack/docs/daytona_target_set.yaml rename to hack/docs/daytona_target-config_create.yaml index 96d66090af..9ca9eba417 100644 --- a/hack/docs/daytona_target_set.yaml +++ b/hack/docs/daytona_target-config_create.yaml @@ -1,6 +1,6 @@ -name: daytona target set -synopsis: Set provider target -usage: daytona target set [flags] +name: daytona target-config create +synopsis: Create target config +usage: daytona target-config create [flags] options: - name: file shorthand: f @@ -11,4 +11,4 @@ inherited_options: default_value: "false" usage: help for daytona see_also: - - daytona target - Manage provider targets + - daytona target-config - Manage target configs diff --git a/hack/docs/daytona_target-config_delete.yaml b/hack/docs/daytona_target-config_delete.yaml new file mode 100644 index 0000000000..922967bd75 --- /dev/null +++ b/hack/docs/daytona_target-config_delete.yaml @@ -0,0 +1,14 @@ +name: daytona target-config delete +synopsis: Deletes a target config +usage: daytona target-config delete [TARGET_CONFIG] [flags] +options: + - name: "yes" + shorthand: "y" + default_value: "false" + usage: Confirm deletion of all targets without prompt +inherited_options: + - name: help + default_value: "false" + usage: help for daytona +see_also: + - daytona target-config - Manage target configs diff --git a/hack/docs/daytona_target-config_list.yaml b/hack/docs/daytona_target-config_list.yaml new file mode 100644 index 0000000000..e909c29023 --- /dev/null +++ b/hack/docs/daytona_target-config_list.yaml @@ -0,0 +1,17 @@ +name: daytona target-config list +synopsis: List target configs +usage: daytona target-config list [flags] +options: + - name: format + shorthand: f + usage: Output format. Must be one of (yaml, json) + - name: show-options + shorthand: v + default_value: "false" + usage: Show target options +inherited_options: + - name: help + default_value: "false" + usage: help for daytona +see_also: + - daytona target-config - Manage target configs diff --git a/hack/docs/daytona_target.yaml b/hack/docs/daytona_target.yaml index 92ce570824..42b77d3d3f 100644 --- a/hack/docs/daytona_target.yaml +++ b/hack/docs/daytona_target.yaml @@ -1,12 +1,18 @@ name: daytona target -synopsis: Manage provider targets +synopsis: Manage targets inherited_options: - name: help default_value: "false" usage: help for daytona see_also: - daytona - Daytona is a Dev Environment Manager + - daytona target create - Create a target + - daytona target delete - Delete a target + - daytona target info - Show target info - daytona target list - List targets - - daytona target remove - Remove target - - daytona target set - Set provider target - - daytona target set-default - Set target to be used by default + - daytona target logs - View the logs of a target + - daytona target restart - Restart a target + - daytona target set-default - Set default target + - daytona target ssh - SSH into a target using the terminal + - daytona target start - Start a target + - daytona target stop - Stop a target diff --git a/hack/docs/daytona_target_create.yaml b/hack/docs/daytona_target_create.yaml new file mode 100644 index 0000000000..dae63af760 --- /dev/null +++ b/hack/docs/daytona_target_create.yaml @@ -0,0 +1,9 @@ +name: daytona target create +synopsis: Create a target +usage: daytona target create [flags] +inherited_options: + - name: help + default_value: "false" + usage: help for daytona +see_also: + - daytona target - Manage targets diff --git a/hack/docs/daytona_target_delete.yaml b/hack/docs/daytona_target_delete.yaml new file mode 100644 index 0000000000..aae2fa1900 --- /dev/null +++ b/hack/docs/daytona_target_delete.yaml @@ -0,0 +1,22 @@ +name: daytona target delete +synopsis: Delete a target +usage: daytona target delete [TARGET]... [flags] +options: + - name: all + shorthand: a + default_value: "false" + usage: Delete all targets + - name: force + shorthand: f + default_value: "false" + usage: Delete a target by force + - name: "yes" + shorthand: "y" + default_value: "false" + usage: Confirm deletion without prompt +inherited_options: + - name: help + default_value: "false" + usage: help for daytona +see_also: + - daytona target - Manage targets diff --git a/hack/docs/daytona_target_info.yaml b/hack/docs/daytona_target_info.yaml new file mode 100644 index 0000000000..41d83cf4fb --- /dev/null +++ b/hack/docs/daytona_target_info.yaml @@ -0,0 +1,17 @@ +name: daytona target info +synopsis: Show target info +usage: daytona target info [TARGET] [flags] +options: + - name: format + shorthand: f + usage: Output format. Must be one of (yaml, json) + - name: show-options + shorthand: v + default_value: "false" + usage: Show target options +inherited_options: + - name: help + default_value: "false" + usage: help for daytona +see_also: + - daytona target - Manage targets diff --git a/hack/docs/daytona_target_list.yaml b/hack/docs/daytona_target_list.yaml index 80c5e8c7de..d65a2dd9fd 100644 --- a/hack/docs/daytona_target_list.yaml +++ b/hack/docs/daytona_target_list.yaml @@ -5,9 +5,13 @@ options: - name: format shorthand: f usage: Output format. Must be one of (yaml, json) + - name: show-options + shorthand: v + default_value: "false" + usage: Show target options inherited_options: - name: help default_value: "false" usage: help for daytona see_also: - - daytona target - Manage provider targets + - daytona target - Manage targets diff --git a/hack/docs/daytona_target_logs.yaml b/hack/docs/daytona_target_logs.yaml new file mode 100644 index 0000000000..17e1a8fde3 --- /dev/null +++ b/hack/docs/daytona_target_logs.yaml @@ -0,0 +1,14 @@ +name: daytona target logs +synopsis: View the logs of a target +usage: daytona target logs [TARGET] [flags] +options: + - name: follow + shorthand: f + default_value: "false" + usage: Follow logs +inherited_options: + - name: help + default_value: "false" + usage: help for daytona +see_also: + - daytona target - Manage targets diff --git a/hack/docs/daytona_target_remove.yaml b/hack/docs/daytona_target_remove.yaml deleted file mode 100644 index ac8a3eebf3..0000000000 --- a/hack/docs/daytona_target_remove.yaml +++ /dev/null @@ -1,14 +0,0 @@ -name: daytona target remove -synopsis: Remove target -usage: daytona target remove [TARGET_NAME] [flags] -options: - - name: "yes" - shorthand: "y" - default_value: "false" - usage: Confirm deletion of all workspaces without prompt -inherited_options: - - name: help - default_value: "false" - usage: help for daytona -see_also: - - daytona target - Manage provider targets diff --git a/hack/docs/daytona_target_restart.yaml b/hack/docs/daytona_target_restart.yaml new file mode 100644 index 0000000000..ca315b438e --- /dev/null +++ b/hack/docs/daytona_target_restart.yaml @@ -0,0 +1,9 @@ +name: daytona target restart +synopsis: Restart a target +usage: daytona target restart [TARGET] [flags] +inherited_options: + - name: help + default_value: "false" + usage: help for daytona +see_also: + - daytona target - Manage targets diff --git a/hack/docs/daytona_target_set-default.yaml b/hack/docs/daytona_target_set-default.yaml index 138758fbd2..cc0f9747e6 100644 --- a/hack/docs/daytona_target_set-default.yaml +++ b/hack/docs/daytona_target_set-default.yaml @@ -1,9 +1,9 @@ name: daytona target set-default -synopsis: Set target to be used by default -usage: daytona target set-default [TARGET_NAME] [flags] +synopsis: Set default target +usage: daytona target set-default [TARGET] [flags] inherited_options: - name: help default_value: "false" usage: help for daytona see_also: - - daytona target - Manage provider targets + - daytona target - Manage targets diff --git a/hack/docs/daytona_target_ssh.yaml b/hack/docs/daytona_target_ssh.yaml new file mode 100644 index 0000000000..4549241c9f --- /dev/null +++ b/hack/docs/daytona_target_ssh.yaml @@ -0,0 +1,18 @@ +name: daytona target ssh +synopsis: SSH into a target using the terminal +usage: daytona target ssh [TARGET] [CMD...] [flags] +options: + - name: option + shorthand: o + default_value: '[]' + usage: Specify SSH options in KEY=VALUE format. + - name: "yes" + shorthand: "y" + default_value: "false" + usage: Automatically confirm any prompts +inherited_options: + - name: help + default_value: "false" + usage: help for daytona +see_also: + - daytona target - Manage targets diff --git a/hack/docs/daytona_target_start.yaml b/hack/docs/daytona_target_start.yaml new file mode 100644 index 0000000000..1803c22237 --- /dev/null +++ b/hack/docs/daytona_target_start.yaml @@ -0,0 +1,18 @@ +name: daytona target start +synopsis: Start a target +usage: daytona target start [TARGET] [flags] +options: + - name: all + shorthand: a + default_value: "false" + usage: Start all targets + - name: "yes" + shorthand: "y" + default_value: "false" + usage: Automatically confirm any prompts +inherited_options: + - name: help + default_value: "false" + usage: help for daytona +see_also: + - daytona target - Manage targets diff --git a/hack/docs/daytona_target_stop.yaml b/hack/docs/daytona_target_stop.yaml new file mode 100644 index 0000000000..356033dafe --- /dev/null +++ b/hack/docs/daytona_target_stop.yaml @@ -0,0 +1,14 @@ +name: daytona target stop +synopsis: Stop a target +usage: daytona target stop [TARGET] [flags] +options: + - name: all + shorthand: a + default_value: "false" + usage: Stop all targets +inherited_options: + - name: help + default_value: "false" + usage: help for daytona +see_also: + - daytona target - Manage targets diff --git a/hack/docs/daytona_template.yaml b/hack/docs/daytona_template.yaml new file mode 100644 index 0000000000..7ac016e143 --- /dev/null +++ b/hack/docs/daytona_template.yaml @@ -0,0 +1,16 @@ +name: daytona template +synopsis: Manage workspace templates +inherited_options: + - name: help + default_value: "false" + usage: help for daytona +see_also: + - daytona - Daytona is a Dev Environment Manager + - daytona template create - Create a workspace template + - daytona template delete - Delete a workspace template + - daytona template export - Export a workspace template + - daytona template import - Import a workspace template from a JSON object + - daytona template info - Show workspace template info + - daytona template list - Lists workspace templates + - daytona template set-default - Set workspace template info + - daytona template update - Update a workspace template diff --git a/hack/docs/daytona_project-config_add.yaml b/hack/docs/daytona_template_create.yaml similarity index 56% rename from hack/docs/daytona_project-config_add.yaml rename to hack/docs/daytona_template_create.yaml index 3e4316f049..4cbac887bf 100644 --- a/hack/docs/daytona_project-config_add.yaml +++ b/hack/docs/daytona_template_create.yaml @@ -1,15 +1,15 @@ -name: daytona project-config add -synopsis: Add a project config -usage: daytona project-config add [flags] +name: daytona template create +synopsis: Create a workspace template +usage: daytona template create [flags] options: - name: builder usage: Specify the builder (currently auto/devcontainer/none) - name: custom-image usage: | - Create the project with the custom image passed as the flag value; Requires setting --custom-image-user flag as well + Create the workspace with the custom image passed as the flag value; Requires setting --custom-image-user flag as well - name: custom-image-user usage: | - Create the project with the custom image user passed as the flag value; Requires setting --custom-image flag as well + Create the workspace with the custom image user passed as the flag value; Requires setting --custom-image flag as well - name: devcontainer-path usage: | Automatically assign the devcontainer builder with the path passed as the flag value @@ -19,14 +19,18 @@ options: Specify environment variables (e.g. --env 'KEY1=VALUE1' --env 'KEY2=VALUE2' ...') - name: git-provider-config usage: Specify the Git provider configuration ID or alias + - name: label + default_value: '[]' + usage: | + Specify labels (e.g. --label 'label.key1=VALUE1' --label 'label.key2=VALUE2' ...) - name: manual default_value: "false" usage: Manually enter the Git repository - name: name - usage: Specify the project config name + usage: Specify the workspace template name inherited_options: - name: help default_value: "false" usage: help for daytona see_also: - - daytona project-config - Manage project configs + - daytona template - Manage workspace templates diff --git a/hack/docs/daytona_project-config_delete.yaml b/hack/docs/daytona_template_delete.yaml similarity index 65% rename from hack/docs/daytona_project-config_delete.yaml rename to hack/docs/daytona_template_delete.yaml index d8399e8b2b..483ea8ab43 100644 --- a/hack/docs/daytona_project-config_delete.yaml +++ b/hack/docs/daytona_template_delete.yaml @@ -1,11 +1,11 @@ -name: daytona project-config delete -synopsis: Delete a project config -usage: daytona project-config delete [flags] +name: daytona template delete +synopsis: Delete a workspace template +usage: daytona template delete [flags] options: - name: all shorthand: a default_value: "false" - usage: Delete all project configs + usage: Delete all workspace templates - name: force shorthand: f default_value: "false" @@ -19,4 +19,4 @@ inherited_options: default_value: "false" usage: help for daytona see_also: - - daytona project-config - Manage project configs + - daytona template - Manage workspace templates diff --git a/hack/docs/daytona_project-config_export.yaml b/hack/docs/daytona_template_export.yaml similarity index 56% rename from hack/docs/daytona_project-config_export.yaml rename to hack/docs/daytona_template_export.yaml index eea3e1aaef..303d7392c0 100644 --- a/hack/docs/daytona_project-config_export.yaml +++ b/hack/docs/daytona_template_export.yaml @@ -1,11 +1,11 @@ -name: daytona project-config export -synopsis: Export a project config -usage: daytona project-config export [flags] +name: daytona template export +synopsis: Export a workspace template +usage: daytona template export [flags] options: - name: all shorthand: a default_value: "false" - usage: Export all project configs + usage: Export all workspace templates - name: format shorthand: f usage: Output format. Must be one of (yaml, json) @@ -14,4 +14,4 @@ inherited_options: default_value: "false" usage: help for daytona see_also: - - daytona project-config - Manage project configs + - daytona template - Manage workspace templates diff --git a/hack/docs/daytona_template_import.yaml b/hack/docs/daytona_template_import.yaml new file mode 100644 index 0000000000..9c6aa6ce98 --- /dev/null +++ b/hack/docs/daytona_template_import.yaml @@ -0,0 +1,14 @@ +name: daytona template import +synopsis: Import a workspace template from a JSON object +usage: daytona template import [flags] +options: + - name: file + shorthand: f + usage: | + Import workspace template from a JSON file. Use '-' to read from stdin. +inherited_options: + - name: help + default_value: "false" + usage: help for daytona +see_also: + - daytona template - Manage workspace templates diff --git a/hack/docs/daytona_project-config_info.yaml b/hack/docs/daytona_template_info.yaml similarity index 55% rename from hack/docs/daytona_project-config_info.yaml rename to hack/docs/daytona_template_info.yaml index c06cbd1981..393928089f 100644 --- a/hack/docs/daytona_project-config_info.yaml +++ b/hack/docs/daytona_template_info.yaml @@ -1,6 +1,6 @@ -name: daytona project-config info -synopsis: Show project config info -usage: daytona project-config info [flags] +name: daytona template info +synopsis: Show workspace template info +usage: daytona template info [flags] options: - name: format shorthand: f @@ -10,4 +10,4 @@ inherited_options: default_value: "false" usage: help for daytona see_also: - - daytona project-config - Manage project configs + - daytona template - Manage workspace templates diff --git a/hack/docs/daytona_git-providers_list.yaml b/hack/docs/daytona_template_list.yaml similarity index 54% rename from hack/docs/daytona_git-providers_list.yaml rename to hack/docs/daytona_template_list.yaml index 002423af47..a59659bbd4 100644 --- a/hack/docs/daytona_git-providers_list.yaml +++ b/hack/docs/daytona_template_list.yaml @@ -1,6 +1,6 @@ -name: daytona git-providers list -synopsis: Lists your registered Git providers -usage: daytona git-providers list [flags] +name: daytona template list +synopsis: Lists workspace templates +usage: daytona template list [flags] options: - name: format shorthand: f @@ -10,4 +10,4 @@ inherited_options: default_value: "false" usage: help for daytona see_also: - - daytona git-providers - Manage Git providers + - daytona template - Manage workspace templates diff --git a/hack/docs/daytona_template_set-default.yaml b/hack/docs/daytona_template_set-default.yaml new file mode 100644 index 0000000000..675b94e95a --- /dev/null +++ b/hack/docs/daytona_template_set-default.yaml @@ -0,0 +1,9 @@ +name: daytona template set-default +synopsis: Set workspace template info +usage: daytona template set-default [flags] +inherited_options: + - name: help + default_value: "false" + usage: help for daytona +see_also: + - daytona template - Manage workspace templates diff --git a/hack/docs/daytona_template_update.yaml b/hack/docs/daytona_template_update.yaml new file mode 100644 index 0000000000..ed459341f7 --- /dev/null +++ b/hack/docs/daytona_template_update.yaml @@ -0,0 +1,9 @@ +name: daytona template update +synopsis: Update a workspace template +usage: daytona template update [flags] +inherited_options: + - name: help + default_value: "false" + usage: help for daytona +see_also: + - daytona template - Manage workspace templates diff --git a/hack/docs/workspace_mode/daytona_logs.yaml b/hack/docs/workspace_mode/daytona_logs.yaml deleted file mode 100644 index 9fe68b0093..0000000000 --- a/hack/docs/workspace_mode/daytona_logs.yaml +++ /dev/null @@ -1,18 +0,0 @@ -name: daytona logs -synopsis: View logs for a workspace/project -usage: daytona logs [WORKSPACE] [PROJECT_NAME] [flags] -options: - - name: follow - shorthand: f - default_value: "false" - usage: Follow logs - - name: workspace - shorthand: w - default_value: "false" - usage: View workspace logs -inherited_options: - - name: help - default_value: "false" - usage: help for daytona -see_also: - - daytona - Use the Daytona CLI to manage your workspace diff --git a/hack/docs/workspace_mode/daytona_restart.yaml b/hack/docs/workspace_mode/daytona_restart.yaml deleted file mode 100644 index 66b72c1775..0000000000 --- a/hack/docs/workspace_mode/daytona_restart.yaml +++ /dev/null @@ -1,9 +0,0 @@ -name: daytona restart -synopsis: Restart the project -usage: daytona restart [flags] -inherited_options: - - name: help - default_value: "false" - usage: help for daytona -see_also: - - daytona - Use the Daytona CLI to manage your workspace diff --git a/hack/docs/workspace_mode/daytona_start.yaml b/hack/docs/workspace_mode/daytona_start.yaml deleted file mode 100644 index b641246389..0000000000 --- a/hack/docs/workspace_mode/daytona_start.yaml +++ /dev/null @@ -1,9 +0,0 @@ -name: daytona start -synopsis: Start the project -usage: daytona start [flags] -inherited_options: - - name: help - default_value: "false" - usage: help for daytona -see_also: - - daytona - Use the Daytona CLI to manage your workspace diff --git a/hack/docs/workspace_mode/daytona_stop.yaml b/hack/docs/workspace_mode/daytona_stop.yaml deleted file mode 100644 index eda52d2732..0000000000 --- a/hack/docs/workspace_mode/daytona_stop.yaml +++ /dev/null @@ -1,9 +0,0 @@ -name: daytona stop -synopsis: Stop the project -usage: daytona stop [flags] -inherited_options: - - name: help - default_value: "false" - usage: help for daytona -see_also: - - daytona - Use the Daytona CLI to manage your workspace diff --git a/hack/generate-cli-docs.sh b/hack/generate-cli-docs.sh index a9504fc1bc..04239cb907 100755 --- a/hack/generate-cli-docs.sh +++ b/hack/generate-cli-docs.sh @@ -7,5 +7,5 @@ rm -rf docs hack/docs # Generate default CLI documentation files in folder "docs" go run cmd/daytona/main.go generate-docs -# Generate workspace mode documentation files in folder "docs/workspace_mode" -DAYTONA_WS_ID=foo go run cmd/daytona/main.go generate-docs --directory docs/workspace_mode \ No newline at end of file +# Generate agent mode documentation files in folder "docs/agent_mode" +DAYTONA_TARGET_ID=foo go run cmd/daytona/main.go generate-docs --directory docs/agent_mode \ No newline at end of file diff --git a/hack/project_image/.devcontainer/devcontainer.json b/hack/workspace_image/.devcontainer/devcontainer.json similarity index 97% rename from hack/project_image/.devcontainer/devcontainer.json rename to hack/workspace_image/.devcontainer/devcontainer.json index 2413e8dab0..1ef04574f3 100644 --- a/hack/project_image/.devcontainer/devcontainer.json +++ b/hack/workspace_image/.devcontainer/devcontainer.json @@ -1,5 +1,5 @@ { - "name": "Daytona Workspace Project", + "name": "Daytona", "build": { "context": "..", "dockerfile": "../Dockerfile" @@ -58,4 +58,4 @@ "ghcr.io/wxw-matt/devcontainer-features/command_runner:latest" ], "remoteUser": "daytona" -} +} \ No newline at end of file diff --git a/hack/project_image/Dockerfile b/hack/workspace_image/Dockerfile similarity index 100% rename from hack/project_image/Dockerfile rename to hack/workspace_image/Dockerfile diff --git a/hack/project_image/docker/postinstall.sh b/hack/workspace_image/docker/postinstall.sh similarity index 100% rename from hack/project_image/docker/postinstall.sh rename to hack/workspace_image/docker/postinstall.sh diff --git a/internal/apikeys/functions.go b/internal/apikeys/functions.go index acd4d6c21d..d5d4939f7a 100644 --- a/internal/apikeys/functions.go +++ b/internal/apikeys/functions.go @@ -5,7 +5,6 @@ package apikeys import ( "encoding/base64" - "encoding/json" "github.com/daytonaio/daytona/internal/util" "github.com/google/uuid" @@ -20,21 +19,3 @@ func GenerateRandomKey() string { uuid := uuid.NewString() return base64.RawStdEncoding.EncodeToString([]byte(uuid)) } - -// Helper function that compares a key with a hash gotten from the API -func EqualsKeyHashFromApi(key string, keyHashFromApi string) bool { - var keyHash string - // We need to marshal then unmarshal the key to mimic the behavior of the API - // Without this, the hash will be different on a byte level - jsonString, err := json.Marshal(HashKey(key)) - if err != nil { - return false - } - - err = json.Unmarshal(jsonString, &keyHash) - if err != nil { - return false - } - - return keyHash == keyHashFromApi -} diff --git a/internal/cmd/tailscale/connection.go b/internal/cmd/tailscale/connection.go index 43fef15419..a801240da1 100644 --- a/internal/cmd/tailscale/connection.go +++ b/internal/cmd/tailscale/connection.go @@ -36,7 +36,7 @@ func GetConnection(profile *config.Profile) (*tsnet.Server, error) { return nil, apiclient_util.HandleErrorResponse(res, err) } - networkKey, res, err := apiClient.ServerAPI.GenerateNetworkKeyExecute(apiclient.ApiGenerateNetworkKeyRequest{}) + networkKey, res, err := apiClient.ServerAPI.CreateNetworkKeyExecute(apiclient.ApiCreateNetworkKeyRequest{}) if err != nil { return nil, apiclient_util.HandleErrorResponse(res, err) } diff --git a/internal/cmd/tailscale/forward.go b/internal/cmd/tailscale/forward.go index d03e06eb80..1958215321 100644 --- a/internal/cmd/tailscale/forward.go +++ b/internal/cmd/tailscale/forward.go @@ -10,12 +10,12 @@ import ( "net" "github.com/daytonaio/daytona/cmd/daytona/config" + "github.com/daytonaio/daytona/pkg/common" "github.com/daytonaio/daytona/pkg/ports" - "github.com/daytonaio/daytona/pkg/workspace/project" "tailscale.com/tsnet" ) -func ForwardPort(workspaceId, projectName string, targetPort uint16, profile config.Profile) (*uint16, chan error) { +func ForwardPort(workspaceId string, targetPort uint16, profile config.Profile) (*uint16, chan error) { hostPort := targetPort errChan := make(chan error) var err error @@ -47,7 +47,7 @@ func ForwardPort(workspaceId, projectName string, targetPort uint16, profile con return } - targetUrl := fmt.Sprintf("%s:%d", project.GetProjectHostname(workspaceId, projectName), targetPort) + targetUrl := fmt.Sprintf("%s:%d", common.GetTailscaleHostname(workspaceId), targetPort) go handlePortConnection(conn, tsConn, targetUrl, errChan) } diff --git a/internal/constants/deleted.go b/internal/constants/deleted.go new file mode 100644 index 0000000000..4144baf107 --- /dev/null +++ b/internal/constants/deleted.go @@ -0,0 +1,6 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package constants + +const DELETED_CIRCUMFIX = "_DELETED_" diff --git a/internal/testing/agent/mocks/apiserver.go b/internal/testing/agent/mocks/apiserver.go index b73034d839..cfdb2a0b91 100644 --- a/internal/testing/agent/mocks/apiserver.go +++ b/internal/testing/agent/mocks/apiserver.go @@ -12,17 +12,15 @@ import ( "testing" "github.com/daytonaio/daytona/pkg/server" - "github.com/daytonaio/daytona/pkg/workspace" "github.com/gin-gonic/gin" ) -func NewMockRestServer(t *testing.T, workspace *workspace.Workspace) *httptest.Server { +func NewMockRestServer(t *testing.T) *httptest.Server { router := gin.Default() serverController := router.Group("/server") { serverController.GET("/config", func(ctx *gin.Context) { ctx.JSON(200, &server.Config{ - ProvidersDir: "", RegistryUrl: "", Id: "", ServerDownloadUrl: "", @@ -37,13 +35,6 @@ func NewMockRestServer(t *testing.T, workspace *workspace.Workspace) *httptest.S }) } - workspaceController := router.Group("/workspace") - { - workspaceController.GET("/:workspaceId", func(ctx *gin.Context) { - ctx.JSON(http.StatusOK, workspace) - }) - } - gitproviderController := router.Group("/gitprovider") { gitproviderController.GET("/for-url/:url", func(ctx *gin.Context) { diff --git a/internal/testing/agent/mocks/docker_cred_helper.go b/internal/testing/agent/mocks/docker_cred_helper.go new file mode 100644 index 0000000000..046d136df8 --- /dev/null +++ b/internal/testing/agent/mocks/docker_cred_helper.go @@ -0,0 +1,24 @@ +//go:build testing + +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package mocks + +import "github.com/stretchr/testify/mock" + +type mockDockerCredHelper struct { + mock.Mock +} + +func (m *mockDockerCredHelper) SetDockerConfig() error { + args := m.Called() + return args.Error(0) +} + +func NewMockDockerCredHelper() *mockDockerCredHelper { + mockCredHelper := new(mockDockerCredHelper) + mockCredHelper.On("SetDockerConfig").Return(nil) + + return mockCredHelper +} diff --git a/internal/testing/build/mocks/build_service.go b/internal/testing/build/mocks/build_service.go index da8936b99f..7d24000b7b 100644 --- a/internal/testing/build/mocks/build_service.go +++ b/internal/testing/build/mocks/build_service.go @@ -6,7 +6,8 @@ package mocks import ( - "github.com/daytonaio/daytona/pkg/build" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/stores" "github.com/stretchr/testify/mock" ) @@ -18,24 +19,24 @@ func NewMockBuildService() *MockBuildService { return &MockBuildService{} } -func (m *MockBuildService) Create(b *build.Build) error { +func (m *MockBuildService) Create(b *models.Build) error { args := m.Called(b) return args.Error(0) } -func (m *MockBuildService) Update(b *build.Build) error { +func (m *MockBuildService) Update(b *models.Build) error { args := m.Called(b) return args.Error(0) } -func (m *MockBuildService) Find(id string) (*build.Build, error) { +func (m *MockBuildService) Find(id string) (*models.Build, error) { args := m.Called(id) - return args.Get(0).(*build.Build), args.Error(1) + return args.Get(0).(*models.Build), args.Error(1) } -func (m *MockBuildService) List(filter *build.Filter) ([]*build.Build, error) { +func (m *MockBuildService) List(filter *stores.BuildFilter) ([]*models.Build, error) { args := m.Called(filter) - return args.Get(0).([]*build.Build), args.Error(1) + return args.Get(0).([]*models.Build), args.Error(1) } func (m *MockBuildService) Delete(id string) error { diff --git a/internal/testing/build/store.go b/internal/testing/build/store.go index 56f54cb1d8..9f1e4fee44 100644 --- a/internal/testing/build/store.go +++ b/internal/testing/build/store.go @@ -6,34 +6,41 @@ package build import ( + "context" "fmt" - "github.com/daytonaio/daytona/pkg/build" + "github.com/daytonaio/daytona/internal/testing/common" + "github.com/daytonaio/daytona/internal/util" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/stores" ) type InMemoryBuildStore struct { - builds map[string]*build.Build + common.InMemoryStore + builds map[string]*models.Build + jobStore stores.JobStore } -func NewInMemoryBuildStore() build.Store { +func NewInMemoryBuildStore(jobStore stores.JobStore) stores.BuildStore { return &InMemoryBuildStore{ - builds: make(map[string]*build.Build), + builds: make(map[string]*models.Build), + jobStore: jobStore, } } -func (s *InMemoryBuildStore) Find(filter *build.Filter) (*build.Build, error) { - builds, err := s.processFilters(filter) +func (s *InMemoryBuildStore) Find(ctx context.Context, filter *stores.BuildFilter) (*models.Build, error) { + b, err := s.processFilters(filter) if err != nil { return nil, err } - if len(builds) == 0 { - return nil, build.ErrBuildNotFound + if len(b) == 0 { + return nil, stores.ErrBuildNotFound } - return builds[0], nil + return b[0], nil } -func (s *InMemoryBuildStore) List(filter *build.Filter) ([]*build.Build, error) { +func (s *InMemoryBuildStore) List(ctx context.Context, filter *stores.BuildFilter) ([]*models.Build, error) { builds, err := s.processFilters(filter) if err != nil { return nil, err @@ -42,51 +49,43 @@ func (s *InMemoryBuildStore) List(filter *build.Filter) ([]*build.Build, error) return builds, nil } -func (s *InMemoryBuildStore) Save(result *build.Build) error { +func (s *InMemoryBuildStore) Save(ctx context.Context, result *models.Build) error { s.builds[result.Id] = result return nil } -func (s *InMemoryBuildStore) Delete(id string) error { +func (s *InMemoryBuildStore) Delete(ctx context.Context, id string) error { delete(s.builds, id) return nil } -func (s *InMemoryBuildStore) processFilters(filter *build.Filter) ([]*build.Build, error) { - var result []*build.Build - filteredBuilds := make(map[string]*build.Build) +func (s *InMemoryBuildStore) processFilters(filter *stores.BuildFilter) ([]*models.Build, error) { + var result []*models.Build + filteredBuilds := make(map[string]*models.Build) for k, v := range s.builds { filteredBuilds[k] = v } + jobs, err := s.jobMap(context.Background()) + if err != nil { + return nil, err + } + if filter != nil { if filter.Id != nil { b, ok := s.builds[*filter.Id] if ok { - return []*build.Build{b}, nil + b.LastJob = jobs[b.Id] + return []*models.Build{b}, nil } else { - return []*build.Build{}, fmt.Errorf("build with id %s not found", *filter.Id) - } - } - if filter.States != nil { - for _, b := range filteredBuilds { - check := false - for _, state := range *filter.States { - if b.State == state { - check = true - break - } - } - if !check { - delete(filteredBuilds, b.Id) - } + return []*models.Build{}, fmt.Errorf("build with id %s not found", *filter.Id) } } if filter.PrebuildIds != nil { for _, b := range filteredBuilds { check := false for _, prebuildId := range *filter.PrebuildIds { - if b.PrebuildId == prebuildId { + if b.PrebuildId != nil && *b.PrebuildId == prebuildId { check = true break } @@ -97,7 +96,7 @@ func (s *InMemoryBuildStore) processFilters(filter *build.Filter) ([]*build.Buil } } if filter.GetNewest != nil && *filter.GetNewest { - var newestBuild *build.Build + var newestBuild *models.Build for _, b := range filteredBuilds { if newestBuild == nil { newestBuild = b @@ -108,7 +107,8 @@ func (s *InMemoryBuildStore) processFilters(filter *build.Filter) ([]*build.Buil } } if newestBuild != nil { - return []*build.Build{newestBuild}, nil + newestBuild.LastJob = jobs[newestBuild.Id] + return []*models.Build{newestBuild}, nil } } if filter.BuildConfig != nil { @@ -149,8 +149,25 @@ func (s *InMemoryBuildStore) processFilters(filter *build.Filter) ([]*build.Buil } for _, b := range filteredBuilds { + b.LastJob = jobs[b.Id] result = append(result, b) } return result, nil } + +func (s *InMemoryBuildStore) jobMap(ctx context.Context) (map[string]*models.Job, error) { + jobs, err := s.jobStore.List(ctx, &stores.JobFilter{ + ResourceType: util.Pointer(models.ResourceTypeWorkspace), + }) + if err != nil { + return nil, err + } + + jobMap := make(map[string]*models.Job) + for _, j := range jobs { + jobMap[j.ResourceId] = j + } + + return jobMap, nil +} diff --git a/internal/testing/common/store.go b/internal/testing/common/store.go new file mode 100644 index 0000000000..66815e5e9b --- /dev/null +++ b/internal/testing/common/store.go @@ -0,0 +1,22 @@ +//go:build testing + +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package common + +import "context" + +type InMemoryStore struct{} + +func (s *InMemoryStore) BeginTransaction(ctx context.Context) (context.Context, error) { + return ctx, nil +} + +func (s *InMemoryStore) CommitTransaction(ctx context.Context) error { + return nil +} + +func (s *InMemoryStore) RollbackTransaction(ctx context.Context, err error) error { + return err +} diff --git a/internal/testing/docker/mocks/client.go b/internal/testing/docker/mocks/client.go index 721f90201c..a119cb5c38 100644 --- a/internal/testing/docker/mocks/client.go +++ b/internal/testing/docker/mocks/client.go @@ -8,10 +8,8 @@ package mocks import ( "io" - "github.com/daytonaio/daytona/pkg/containerregistry" "github.com/daytonaio/daytona/pkg/docker" - "github.com/daytonaio/daytona/pkg/workspace" - "github.com/daytonaio/daytona/pkg/workspace/project" + "github.com/daytonaio/daytona/pkg/models" "github.com/docker/docker/api/types/container" "github.com/stretchr/testify/mock" ) @@ -25,48 +23,38 @@ func NewMockClient() *MockClient { return &MockClient{} } -func (c *MockClient) CreateProject(p *project.Project, serverDownloadUrl string, cr *containerregistry.ContainerRegistry, logWriter io.Writer) error { - args := c.Called(p, serverDownloadUrl, cr, logWriter) +func (c *MockClient) CreateWorkspace(w *models.Workspace, serverDownloadUrl string, cr *models.ContainerRegistry, logWriter io.Writer) error { + args := c.Called(w, serverDownloadUrl, cr, logWriter) return args.Error(0) } -func (c *MockClient) CreateWorkspace(workspace *workspace.Workspace, logWriter io.Writer) error { - args := c.Called(workspace, logWriter) +func (c *MockClient) CreateTarget(target *models.Target, logWriter io.Writer) error { + args := c.Called(target, logWriter) return args.Error(0) } -func (c *MockClient) DestroyProject(p *project.Project) error { - args := c.Called(p) +func (c *MockClient) DestroyWorkspace(w *models.Workspace) error { + args := c.Called(w) return args.Error(0) } -func (c *MockClient) DestroyWorkspace(workspace *workspace.Workspace) error { - args := c.Called(workspace) +func (c *MockClient) DestroyTarget(target *models.Target) error { + args := c.Called(target) return args.Error(0) } -func (c *MockClient) StartProject(p *project.Project) error { - args := c.Called(p) +func (c *MockClient) StartWorkspace(w *models.Workspace) error { + args := c.Called(w) return args.Error(0) } -func (c *MockClient) StopProject(p *project.Project) error { - args := c.Called(p) +func (c *MockClient) StopWorkspace(w *models.Workspace) error { + args := c.Called(w) return args.Error(0) } -func (c *MockClient) GetProjectInfo(p *project.Project) (*project.ProjectInfo, error) { - args := c.Called(p) - return args.Get(0).(*project.ProjectInfo), args.Error(1) -} - -func (c *MockClient) GetWorkspaceInfo(ws *workspace.Workspace) (*workspace.WorkspaceInfo, error) { - args := c.Called(ws) - return args.Get(0).(*workspace.WorkspaceInfo), args.Error(1) -} - -func (c *MockClient) GetProjectContainerName(p *project.Project) string { - args := c.Called(p) +func (c *MockClient) GetWorkspaceContainerName(w *models.Workspace) string { + args := c.Called(w) return args.String(0) } diff --git a/internal/testing/git/mocks/gitservice.go b/internal/testing/git/mocks/gitservice.go index 99ea2a30a8..5d96540435 100644 --- a/internal/testing/git/mocks/gitservice.go +++ b/internal/testing/git/mocks/gitservice.go @@ -7,7 +7,7 @@ package mocks import ( "github.com/daytonaio/daytona/pkg/gitprovider" - "github.com/daytonaio/daytona/pkg/workspace/project" + "github.com/daytonaio/daytona/pkg/models" "github.com/go-git/go-git/v5/plumbing/transport/http" "github.com/stretchr/testify/mock" ) @@ -31,14 +31,14 @@ func (m *MockGitService) RepositoryExists() (bool, error) { return args.Bool(0), args.Error(1) } -func (m *MockGitService) SetGitConfig(userData *gitprovider.GitUser, providerConfig *gitprovider.GitProviderConfig) error { +func (m *MockGitService) SetGitConfig(userData *gitprovider.GitUser, providerConfig *models.GitProviderConfig) error { args := m.Called(userData, providerConfig) return args.Error(0) } -func (m *MockGitService) GetGitStatus() (*project.GitStatus, error) { +func (m *MockGitService) GetGitStatus() (*models.GitStatus, error) { args := m.Called() - return args.Get(0).(*project.GitStatus), args.Error(1) + return args.Get(0).(*models.GitStatus), args.Error(1) } func NewMockGitService() *MockGitService { diff --git a/internal/testing/job/store.go b/internal/testing/job/store.go new file mode 100644 index 0000000000..3f793e76c2 --- /dev/null +++ b/internal/testing/job/store.go @@ -0,0 +1,117 @@ +//go:build testing + +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package job + +import ( + "context" + "fmt" + + "github.com/daytonaio/daytona/internal/testing/common" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/stores" +) + +type InMemoryJobStore struct { + common.InMemoryStore + jobs map[string]*models.Job +} + +func NewInMemoryJobStore() stores.JobStore { + return &InMemoryJobStore{ + jobs: make(map[string]*models.Job), + } +} + +func (s *InMemoryJobStore) List(ctx context.Context, filter *stores.JobFilter) ([]*models.Job, error) { + jobs, err := s.processFilters(filter) + if err != nil { + return nil, err + } + + return jobs, nil +} + +func (s *InMemoryJobStore) Find(ctx context.Context, filter *stores.JobFilter) (*models.Job, error) { + jobs, err := s.processFilters(filter) + if err != nil { + return nil, err + } + if len(jobs) == 0 { + return nil, stores.ErrJobNotFound + } + + return jobs[0], nil +} + +func (s *InMemoryJobStore) Save(ctx context.Context, job *models.Job) error { + s.jobs[job.Id] = job + return nil +} + +func (s *InMemoryJobStore) Delete(ctx context.Context, job *models.Job) error { + delete(s.jobs, job.Id) + return nil +} + +func (s *InMemoryJobStore) processFilters(filter *stores.JobFilter) ([]*models.Job, error) { + var result []*models.Job + filteredJobs := make(map[string]*models.Job) + for k, v := range s.jobs { + filteredJobs[k] = v + } + + if filter != nil { + if filter.Id != nil { + job, ok := s.jobs[*filter.Id] + if ok { + return []*models.Job{job}, nil + } else { + return []*models.Job{}, fmt.Errorf("job with id %s not found", *filter.Id) + } + } + if filter.States != nil { + for _, job := range filteredJobs { + check := false + for _, state := range *filter.States { + if job.State == state { + check = true + break + } + } + if !check { + delete(filteredJobs, job.Id) + } + } + } + if filter.Actions != nil { + for _, job := range filteredJobs { + check := false + for _, action := range *filter.Actions { + if job.Action == action { + check = true + break + } + } + if !check { + delete(filteredJobs, job.Id) + } + } + } + if filter.ResourceId != nil { + for _, job := range filteredJobs { + if job.ResourceId != *filter.ResourceId { + delete(filteredJobs, job.Id) + } + } + } + } + + for _, job := range filteredJobs { + result = append(result, job) + } + + return result, nil +} diff --git a/internal/testing/logger/mocks/logger.go b/internal/testing/logger/mocks/logger.go index 9ffb1bebfe..55b916b731 100644 --- a/internal/testing/logger/mocks/logger.go +++ b/internal/testing/logger/mocks/logger.go @@ -20,27 +20,27 @@ type MockLoggerFactory struct { mock.Mock } -func (f *MockLoggerFactory) CreateWorkspaceLogger(workspaceId string, source logs.LogSource) logs.Logger { +func (f *MockLoggerFactory) CreateTargetLogger(targetId string, source logs.LogSource) logs.Logger { return &mockLogger{} } -func (f *MockLoggerFactory) CreateProjectLogger(workspaceId, projectName string, source logs.LogSource) logs.Logger { +func (f *MockLoggerFactory) CreateWorkspaceLogger(targetId, workspaceName string, source logs.LogSource) logs.Logger { return &mockLogger{} } -func (f *MockLoggerFactory) CreateBuildLogger(projectName, hash string, source logs.LogSource) logs.Logger { +func (f *MockLoggerFactory) CreateBuildLogger(workspaceName, hash string, source logs.LogSource) logs.Logger { return &mockLogger{} } -func (f *MockLoggerFactory) CreateWorkspaceLogReader(workspaceId string) (io.Reader, error) { +func (f *MockLoggerFactory) CreateTargetLogReader(targetId string) (io.Reader, error) { return nil, nil } -func (f *MockLoggerFactory) CreateProjectLogReader(workspaceId, projectName string) (io.Reader, error) { +func (f *MockLoggerFactory) CreateWorkspaceLogReader(targetId, workspaceName string) (io.Reader, error) { return nil, nil } -func (f *MockLoggerFactory) CreateBuildLogReader(projectName, hash string) (io.Reader, error) { +func (f *MockLoggerFactory) CreateBuildLogReader(workspaceName, hash string) (io.Reader, error) { return nil, nil } @@ -53,6 +53,11 @@ func (m *mockLogger) Write(p []byte) (n int, err error) { return args.Int(0), args.Error(1) } +func (m *mockLogger) ConstructJsonLogEntry(p []byte) ([]byte, error) { + args := m.Called(p) + return args.Get(0).([]byte), args.Error(1) +} + func (m *mockLogger) Close() error { args := m.Called() return args.Error(0) diff --git a/internal/testing/provider/targets/store.go b/internal/testing/provider/targets/store.go deleted file mode 100644 index 160089e340..0000000000 --- a/internal/testing/provider/targets/store.go +++ /dev/null @@ -1,80 +0,0 @@ -//go:build testing - -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package targets - -import ( - "fmt" - - "github.com/daytonaio/daytona/pkg/provider" -) - -type InMemoryTargetStore struct { - targets map[string]*provider.ProviderTarget -} - -func NewInMemoryTargetStore() provider.TargetStore { - return &InMemoryTargetStore{ - targets: make(map[string]*provider.ProviderTarget), - } -} - -func (s *InMemoryTargetStore) List(filter *provider.TargetFilter) ([]*provider.ProviderTarget, error) { - return s.processFilters(filter) -} - -func (s *InMemoryTargetStore) Find(filter *provider.TargetFilter) (*provider.ProviderTarget, error) { - targets, err := s.processFilters(filter) - if err != nil { - return nil, err - } - if len(targets) == 0 { - return nil, provider.ErrTargetNotFound - } - - return targets[0], nil -} - -func (s *InMemoryTargetStore) Save(target *provider.ProviderTarget) error { - s.targets[target.Name] = target - return nil -} - -func (s *InMemoryTargetStore) Delete(target *provider.ProviderTarget) error { - delete(s.targets, target.Name) - return nil -} - -func (s *InMemoryTargetStore) processFilters(filter *provider.TargetFilter) ([]*provider.ProviderTarget, error) { - var result []*provider.ProviderTarget - filteredTargets := make(map[string]*provider.ProviderTarget) - for k, v := range s.targets { - filteredTargets[k] = v - } - - if filter != nil { - if filter.Name != nil { - target, ok := s.targets[*filter.Name] - if ok { - return []*provider.ProviderTarget{target}, nil - } else { - return []*provider.ProviderTarget{}, fmt.Errorf("target with name %s not found", *filter.Name) - } - } - if filter.Default != nil { - for _, target := range filteredTargets { - if target.IsDefault != *filter.Default { - delete(filteredTargets, target.Name) - } - } - } - } - - for _, target := range filteredTargets { - result = append(result, target) - } - - return result, nil -} diff --git a/internal/testing/server/apikeys/store.go b/internal/testing/server/apikeys/store.go index 63fd23d0c9..d392a64ba6 100644 --- a/internal/testing/server/apikeys/store.go +++ b/internal/testing/server/apikeys/store.go @@ -6,21 +6,26 @@ package apikeys import ( - "github.com/daytonaio/daytona/pkg/apikey" + "context" + + "github.com/daytonaio/daytona/internal/testing/common" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/stores" ) type InMemoryApiKeyStore struct { - apiKeys map[string]*apikey.ApiKey + common.InMemoryStore + apiKeys map[string]*models.ApiKey } -func NewInMemoryApiKeyStore() apikey.Store { +func NewInMemoryApiKeyStore() stores.ApiKeyStore { return &InMemoryApiKeyStore{ - apiKeys: make(map[string]*apikey.ApiKey), + apiKeys: make(map[string]*models.ApiKey), } } -func (s *InMemoryApiKeyStore) List() ([]*apikey.ApiKey, error) { - apiKeys := []*apikey.ApiKey{} +func (s *InMemoryApiKeyStore) List(ctx context.Context) ([]*models.ApiKey, error) { + apiKeys := []*models.ApiKey{} for _, a := range s.apiKeys { apiKeys = append(apiKeys, a) } @@ -28,16 +33,16 @@ func (s *InMemoryApiKeyStore) List() ([]*apikey.ApiKey, error) { return apiKeys, nil } -func (s *InMemoryApiKeyStore) Find(key string) (*apikey.ApiKey, error) { +func (s *InMemoryApiKeyStore) Find(ctx context.Context, key string) (*models.ApiKey, error) { apiKey, ok := s.apiKeys[key] if !ok { - return nil, apikey.ErrApiKeyNotFound + return nil, stores.ErrApiKeyNotFound } return apiKey, nil } -func (s *InMemoryApiKeyStore) FindByName(name string) (*apikey.ApiKey, error) { +func (s *InMemoryApiKeyStore) FindByName(ctx context.Context, name string) (*models.ApiKey, error) { for _, a := range s.apiKeys { if a.Name == name { return a, nil @@ -47,12 +52,12 @@ func (s *InMemoryApiKeyStore) FindByName(name string) (*apikey.ApiKey, error) { return nil, nil } -func (s *InMemoryApiKeyStore) Save(apiKey *apikey.ApiKey) error { +func (s *InMemoryApiKeyStore) Save(ctx context.Context, apiKey *models.ApiKey) error { s.apiKeys[apiKey.KeyHash] = apiKey return nil } -func (s *InMemoryApiKeyStore) Delete(apiKey *apikey.ApiKey) error { +func (s *InMemoryApiKeyStore) Delete(ctx context.Context, apiKey *models.ApiKey) error { delete(s.apiKeys, apiKey.KeyHash) return nil } diff --git a/internal/testing/server/containerregistries/store.go b/internal/testing/server/containerregistries/store.go deleted file mode 100644 index c3adb67066..0000000000 --- a/internal/testing/server/containerregistries/store.go +++ /dev/null @@ -1,52 +0,0 @@ -//go:build testing - -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package containerregistries - -import ( - "github.com/daytonaio/daytona/pkg/containerregistry" -) - -type InMemoryContainerRegistryStore struct { - crs map[string]*containerregistry.ContainerRegistry -} - -func NewInMemoryContainerRegistryStore() containerregistry.Store { - return &InMemoryContainerRegistryStore{ - crs: make(map[string]*containerregistry.ContainerRegistry), - } -} - -func (s *InMemoryContainerRegistryStore) List() ([]*containerregistry.ContainerRegistry, error) { - crs := []*containerregistry.ContainerRegistry{} - for _, cr := range s.crs { - crs = append(crs, cr) - } - - return crs, nil -} - -func (s *InMemoryContainerRegistryStore) Find(server string) (*containerregistry.ContainerRegistry, error) { - cr, ok := s.crs[server] - if !ok { - return nil, containerregistry.ErrContainerRegistryNotFound - } - - return cr, nil -} - -func (s *InMemoryContainerRegistryStore) Save(cr *containerregistry.ContainerRegistry) error { - s.crs[cr.Server] = cr - return nil -} - -func (s *InMemoryContainerRegistryStore) Delete(cr *containerregistry.ContainerRegistry) error { - _, ok := s.crs[cr.Server] - if !ok { - return containerregistry.ErrContainerRegistryNotFound - } - delete(s.crs, cr.Server) - return nil -} diff --git a/internal/testing/server/env/store.go b/internal/testing/server/env/store.go new file mode 100644 index 0000000000..b1fde9cc2f --- /dev/null +++ b/internal/testing/server/env/store.go @@ -0,0 +1,48 @@ +//go:build testing + +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package env + +import ( + "context" + + "github.com/daytonaio/daytona/internal/testing/common" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/stores" +) + +type InMemoryEnvironmentVariableStore struct { + common.InMemoryStore + envVars map[string]*models.EnvironmentVariable +} + +func NewInMemoryEnvironmentVariableStore() stores.EnvironmentVariableStore { + return &InMemoryEnvironmentVariableStore{ + envVars: make(map[string]*models.EnvironmentVariable), + } +} + +func (s *InMemoryEnvironmentVariableStore) List(ctx context.Context) ([]*models.EnvironmentVariable, error) { + envVars := []*models.EnvironmentVariable{} + for _, envVar := range s.envVars { + envVars = append(envVars, envVar) + } + + return envVars, nil +} + +func (s *InMemoryEnvironmentVariableStore) Save(ctx context.Context, environmentVariable *models.EnvironmentVariable) error { + s.envVars[environmentVariable.Key] = environmentVariable + return nil +} + +func (s *InMemoryEnvironmentVariableStore) Delete(ctx context.Context, key string) error { + _, ok := s.envVars[key] + if !ok { + return stores.ErrEnvironmentVariableNotFound + } + delete(s.envVars, key) + return nil +} diff --git a/internal/testing/server/profiledata/store.go b/internal/testing/server/profiledata/store.go deleted file mode 100644 index 0f88efbc63..0000000000 --- a/internal/testing/server/profiledata/store.go +++ /dev/null @@ -1,38 +0,0 @@ -//go:build testing - -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package profiledata - -import ( - "github.com/daytonaio/daytona/pkg/profiledata" -) - -type InMemoryProfileDataStore struct { - profileData *profiledata.ProfileData -} - -func NewInMemoryProfileDataStore() profiledata.Store { - return &InMemoryProfileDataStore{ - profileData: nil, - } -} - -func (s *InMemoryProfileDataStore) Get() (*profiledata.ProfileData, error) { - if s.profileData == nil { - return nil, profiledata.ErrProfileDataNotFound - } - - return s.profileData, nil -} - -func (s *InMemoryProfileDataStore) Save(profileData *profiledata.ProfileData) error { - s.profileData = profileData - return nil -} - -func (s *InMemoryProfileDataStore) Delete() error { - s.profileData = nil - return nil -} diff --git a/internal/testing/server/projectconfig/store.go b/internal/testing/server/projectconfig/store.go deleted file mode 100644 index b2f19e60e7..0000000000 --- a/internal/testing/server/projectconfig/store.go +++ /dev/null @@ -1,94 +0,0 @@ -//go:build testing - -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package projectconfig - -import ( - "fmt" - - "github.com/daytonaio/daytona/pkg/workspace/project/config" -) - -type InMemoryProjectConfigStore struct { - projectConfigs map[string]*config.ProjectConfig -} - -func NewInMemoryProjectConfigStore() config.Store { - return &InMemoryProjectConfigStore{ - projectConfigs: make(map[string]*config.ProjectConfig), - } -} - -func (s *InMemoryProjectConfigStore) List(filter *config.ProjectConfigFilter) ([]*config.ProjectConfig, error) { - return s.processFilters(filter) -} - -func (s *InMemoryProjectConfigStore) Find(filter *config.ProjectConfigFilter) (*config.ProjectConfig, error) { - projectConfigs, err := s.processFilters(filter) - if err != nil { - return nil, err - } - if len(projectConfigs) == 0 { - return nil, config.ErrProjectConfigNotFound - } - - return projectConfigs[0], nil -} - -func (s *InMemoryProjectConfigStore) Save(projectConfig *config.ProjectConfig) error { - s.projectConfigs[projectConfig.Name] = projectConfig - return nil -} - -func (s *InMemoryProjectConfigStore) Delete(projectConfig *config.ProjectConfig) error { - delete(s.projectConfigs, projectConfig.Name) - return nil -} - -func (s *InMemoryProjectConfigStore) processFilters(filter *config.ProjectConfigFilter) ([]*config.ProjectConfig, error) { - var result []*config.ProjectConfig - filteredProjectConfigs := make(map[string]*config.ProjectConfig) - for k, v := range s.projectConfigs { - filteredProjectConfigs[k] = v - } - - if filter != nil { - if filter.Name != nil { - projectConfig, ok := s.projectConfigs[*filter.Name] - if ok { - return []*config.ProjectConfig{projectConfig}, nil - } else { - return []*config.ProjectConfig{}, fmt.Errorf("project config with name %s not found", *filter.Name) - } - } - if filter.Url != nil { - for _, projectConfig := range filteredProjectConfigs { - if projectConfig.RepositoryUrl != *filter.Url { - delete(filteredProjectConfigs, projectConfig.Name) - } - } - } - if filter.Default != nil { - for _, projectConfig := range filteredProjectConfigs { - if projectConfig.IsDefault != *filter.Default { - delete(filteredProjectConfigs, projectConfig.Name) - } - } - } - if filter.GitProviderConfigId != nil { - for _, projectConfig := range filteredProjectConfigs { - if projectConfig.GitProviderConfigId != nil && *projectConfig.GitProviderConfigId != *filter.GitProviderConfigId { - delete(filteredProjectConfigs, projectConfig.Name) - } - } - } - } - - for _, projectConfig := range filteredProjectConfigs { - result = append(result, projectConfig) - } - - return result, nil -} diff --git a/internal/testing/server/targetconfigs/store.go b/internal/testing/server/targetconfigs/store.go new file mode 100644 index 0000000000..f942b97e5d --- /dev/null +++ b/internal/testing/server/targetconfigs/store.go @@ -0,0 +1,74 @@ +//go:build testing + +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package targetconfigs + +import ( + "context" + + "github.com/daytonaio/daytona/internal/testing/common" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/stores" +) + +type InMemoryTargetConfigStore struct { + common.InMemoryStore + targetConfigs map[string]*models.TargetConfig +} + +func NewInMemoryTargetConfigStore() stores.TargetConfigStore { + return &InMemoryTargetConfigStore{ + targetConfigs: make(map[string]*models.TargetConfig), + } +} + +func (s *InMemoryTargetConfigStore) List(ctx context.Context, allowDeleted bool) ([]*models.TargetConfig, error) { + return s.processFilters("", allowDeleted) +} + +func (s *InMemoryTargetConfigStore) Find(ctx context.Context, idOrName string, allowDeleted bool) (*models.TargetConfig, error) { + targets, err := s.processFilters(idOrName, allowDeleted) + if err != nil { + return nil, err + } + + if len(targets) == 0 { + return nil, stores.ErrTargetConfigNotFound + } + + return targets[0], nil +} + +func (s *InMemoryTargetConfigStore) Save(ctx context.Context, targetConfig *models.TargetConfig) error { + s.targetConfigs[targetConfig.Id] = targetConfig + return nil +} + +func (s *InMemoryTargetConfigStore) processFilters(idOrName string, allowDeleted bool) ([]*models.TargetConfig, error) { + var result []*models.TargetConfig + + if idOrName != "" { + t, ok := s.targetConfigs[idOrName] + if ok { + result = append(result, t) + } + } else { + for _, targetConfig := range s.targetConfigs { + result = append(result, targetConfig) + } + } + + if !allowDeleted { + notDeleted := []*models.TargetConfig{} + for _, targetConfig := range result { + if !targetConfig.Deleted { + notDeleted = append(notDeleted, targetConfig) + } + } + result = notDeleted + } + + return result, nil +} diff --git a/internal/testing/server/targets/metadata_store.go b/internal/testing/server/targets/metadata_store.go new file mode 100644 index 0000000000..e3ad8e6201 --- /dev/null +++ b/internal/testing/server/targets/metadata_store.go @@ -0,0 +1,44 @@ +//go:build testing + +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package targets + +import ( + "context" + + "github.com/daytonaio/daytona/internal/testing/common" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/stores" +) + +type InMemoryTargetMetadataStore struct { + common.InMemoryStore + targetMetadataEntries map[string]*models.TargetMetadata +} + +func NewInMemoryTargetMetadataStore() stores.TargetMetadataStore { + return &InMemoryTargetMetadataStore{ + targetMetadataEntries: make(map[string]*models.TargetMetadata), + } +} + +func (s *InMemoryTargetMetadataStore) Find(ctx context.Context, targetId string) (*models.TargetMetadata, error) { + metadata, ok := s.targetMetadataEntries[targetId] + if !ok { + return nil, stores.ErrTargetMetadataNotFound + } + + return metadata, nil +} + +func (s *InMemoryTargetMetadataStore) Save(ctx context.Context, targetMetadata *models.TargetMetadata) error { + s.targetMetadataEntries[targetMetadata.TargetId] = targetMetadata + return nil +} + +func (s *InMemoryTargetMetadataStore) Delete(ctx context.Context, targetMetadata *models.TargetMetadata) error { + delete(s.targetMetadataEntries, targetMetadata.TargetId) + return nil +} diff --git a/internal/testing/server/workspaces/mocks/api_key_service.go b/internal/testing/server/targets/mocks/api_key_service.go similarity index 65% rename from internal/testing/server/workspaces/mocks/api_key_service.go rename to internal/testing/server/targets/mocks/api_key_service.go index dfdfccc7ea..12ca222b18 100644 --- a/internal/testing/server/workspaces/mocks/api_key_service.go +++ b/internal/testing/server/targets/mocks/api_key_service.go @@ -6,7 +6,7 @@ package mocks import ( - "github.com/daytonaio/daytona/pkg/apikey" + "github.com/daytonaio/daytona/pkg/models" "github.com/stretchr/testify/mock" ) @@ -18,12 +18,12 @@ func NewMockApiKeyService() *mockApiKeyService { return &mockApiKeyService{} } -func (s *mockApiKeyService) Generate(keyType apikey.ApiKeyType, name string) (string, error) { +func (s *mockApiKeyService) Create(keyType models.ApiKeyType, name string) (string, error) { args := s.Called(keyType, name) return args.String(0), args.Error(1) } -func (s *mockApiKeyService) IsProjectApiKey(apiKey string) bool { +func (s *mockApiKeyService) IsWorkspaceApiKey(apiKey string) bool { args := s.Called(apiKey) return args.Bool(0) } @@ -33,17 +33,17 @@ func (s *mockApiKeyService) IsValidApiKey(apiKey string) bool { return args.Bool(0) } -func (s *mockApiKeyService) IsWorkspaceApiKey(apiKey string) bool { +func (s *mockApiKeyService) IsTargetApiKey(apiKey string) bool { args := s.Called(apiKey) return args.Bool(0) } -func (s *mockApiKeyService) ListClientKeys() ([]*apikey.ApiKey, error) { +func (s *mockApiKeyService) ListClientKeys() ([]*models.ApiKey, error) { args := s.Called() - return args.Get(0).([]*apikey.ApiKey), args.Error(1) + return args.Get(0).([]*models.ApiKey), args.Error(1) } -func (s *mockApiKeyService) Revoke(name string) error { +func (s *mockApiKeyService) Delete(name string) error { args := s.Called(name) return args.Error(0) } diff --git a/internal/testing/server/targets/mocks/build_service.go b/internal/testing/server/targets/mocks/build_service.go new file mode 100644 index 0000000000..13162b1846 --- /dev/null +++ b/internal/testing/server/targets/mocks/build_service.go @@ -0,0 +1,51 @@ +//go:build testing + +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package mocks + +import ( + "io" + + "github.com/daytonaio/daytona/pkg/services" + "github.com/stretchr/testify/mock" +) + +type MockBuildService struct { + mock.Mock +} + +func NewMockBuildService() *MockBuildService { + return &MockBuildService{} +} + +func (m *MockBuildService) Create(createBuildDto services.CreateBuildDTO) (string, error) { + args := m.Called(createBuildDto) + return args.String(0), args.Error(1) +} + +func (m *MockBuildService) Find(filter *services.BuildFilter) (*services.BuildDTO, error) { + args := m.Called(filter) + return args.Get(0).(*services.BuildDTO), args.Error(1) +} + +func (m *MockBuildService) List(filter *services.BuildFilter) ([]*services.BuildDTO, error) { + args := m.Called(filter) + return args.Get(0).([]*services.BuildDTO), args.Error(1) +} + +func (m *MockBuildService) Delete(filter *services.BuildFilter, force bool) []error { + args := m.Called(filter, force) + return args.Get(0).([]error) +} + +func (m *MockBuildService) HandleSuccessfulRemoval(id string) error { + args := m.Called(id) + return args.Get(0).(error) +} + +func (m *MockBuildService) GetBuildLogReader(buildId string) (io.Reader, error) { + args := m.Called(buildId) + return args.Get(0).(io.Reader), args.Error(1) +} diff --git a/internal/testing/server/workspaces/mocks/builder.go b/internal/testing/server/targets/mocks/builder.go similarity index 50% rename from internal/testing/server/workspaces/mocks/builder.go rename to internal/testing/server/targets/mocks/builder.go index 19981d217d..baff40d775 100644 --- a/internal/testing/server/workspaces/mocks/builder.go +++ b/internal/testing/server/targets/mocks/builder.go @@ -9,25 +9,23 @@ import ( "github.com/daytonaio/daytona/internal/util" "github.com/daytonaio/daytona/pkg/build" "github.com/daytonaio/daytona/pkg/gitprovider" - "github.com/daytonaio/daytona/pkg/workspace/project/buildconfig" - "github.com/daytonaio/daytona/pkg/workspace/project/containerconfig" + "github.com/daytonaio/daytona/pkg/models" "github.com/stretchr/testify/mock" ) -var MockBuild = &build.Build{ +var MockBuild = &models.Build{ Id: "1", - State: build.BuildStatePendingRun, Image: util.Pointer("image"), User: util.Pointer("user"), - ContainerConfig: containerconfig.ContainerConfig{ + ContainerConfig: models.ContainerConfig{ Image: "test", User: "test", }, - BuildConfig: &buildconfig.BuildConfig{ - Devcontainer: MockProjectConfig.BuildConfig.Devcontainer, + BuildConfig: &models.BuildConfig{ + Devcontainer: MockWorkspaceTemplate.BuildConfig.Devcontainer, }, Repository: &gitprovider.GitRepository{ - Url: MockProjectConfig.RepositoryUrl, + Url: MockWorkspaceTemplate.RepositoryUrl, }, EnvVars: map[string]string{}, } @@ -36,21 +34,16 @@ type MockBuilderFactory struct { mock.Mock } -func (f *MockBuilderFactory) Create(build build.Build, projectDir string) (build.IBuilder, error) { - args := f.Called(build, projectDir) +func (f *MockBuilderFactory) Create(build models.Build, workspaceDir string) (build.IBuilder, error) { + args := f.Called(build, workspaceDir) return args.Get(0).(*MockBuilder), args.Error(1) } -func (f *MockBuilderFactory) CheckExistingBuild(b build.Build) (*build.Build, error) { - args := f.Called(b) - return args.Get(0).(*build.Build), args.Error(1) -} - type MockBuilder struct { mock.Mock } -func (b *MockBuilder) Build(build build.Build) (string, string, error) { +func (b *MockBuilder) Build(build models.Build) (string, string, error) { args := b.Called(build) return args.String(0), args.String(1), args.Error(2) } @@ -60,17 +53,17 @@ func (b *MockBuilder) CleanUp() error { return args.Error(0) } -func (b *MockBuilder) Publish(build build.Build) error { +func (b *MockBuilder) Publish(build models.Build) error { args := b.Called(build) return args.Error(0) } -func (b *MockBuilder) SaveBuild(r build.Build) error { +func (b *MockBuilder) SaveBuild(r models.Build) error { args := b.Called(r) return args.Error(0) } -func (b *MockBuilder) GetImageName(build build.Build) (string, error) { +func (b *MockBuilder) GetImageName(build models.Build) (string, error) { args := b.Called(build) return args.String(0), args.Error(1) } diff --git a/internal/testing/server/workspaces/mocks/git_provider_service.go b/internal/testing/server/targets/mocks/git_provider_service.go similarity index 84% rename from internal/testing/server/workspaces/mocks/git_provider_service.go rename to internal/testing/server/targets/mocks/git_provider_service.go index a58a54c763..fda6641879 100644 --- a/internal/testing/server/workspaces/mocks/git_provider_service.go +++ b/internal/testing/server/targets/mocks/git_provider_service.go @@ -9,6 +9,7 @@ import ( "net/http" "github.com/daytonaio/daytona/pkg/gitprovider" + "github.com/daytonaio/daytona/pkg/models" "github.com/stretchr/testify/mock" ) @@ -20,14 +21,14 @@ func NewMockGitProviderService() *MockGitProviderService { return &MockGitProviderService{} } -func (m *MockGitProviderService) GetConfig(id string) (*gitprovider.GitProviderConfig, error) { +func (m *MockGitProviderService) FindConfig(id string) (*models.GitProviderConfig, error) { args := m.Called(id) - return args.Get(0).(*gitprovider.GitProviderConfig), args.Error(1) + return args.Get(0).(*models.GitProviderConfig), args.Error(1) } -func (m *MockGitProviderService) ListConfigsForUrl(url string) ([]*gitprovider.GitProviderConfig, error) { +func (m *MockGitProviderService) ListConfigsForUrl(url string) ([]*models.GitProviderConfig, error) { args := m.Called(url) - return args.Get(0).([]*gitprovider.GitProviderConfig), args.Error(1) + return args.Get(0).([]*models.GitProviderConfig), args.Error(1) } func (m *MockGitProviderService) GetGitProviderForHttpRequest(req *http.Request) (gitprovider.GitProvider, error) { @@ -70,17 +71,17 @@ func (m *MockGitProviderService) GetRepositories(gitProviderId string, namespace return args.Get(0).([]*gitprovider.GitRepository), args.Error(1) } -func (m *MockGitProviderService) ListConfigs() ([]*gitprovider.GitProviderConfig, error) { +func (m *MockGitProviderService) ListConfigs() ([]*models.GitProviderConfig, error) { args := m.Called() - return args.Get(0).([]*gitprovider.GitProviderConfig), args.Error(1) + return args.Get(0).([]*models.GitProviderConfig), args.Error(1) } -func (m *MockGitProviderService) RemoveGitProvider(gitProviderId string) error { +func (m *MockGitProviderService) DeleteGitProvider(gitProviderId string) error { args := m.Called(gitProviderId) return args.Error(0) } -func (m *MockGitProviderService) SetGitProviderConfig(providerConfig *gitprovider.GitProviderConfig) error { +func (m *MockGitProviderService) SaveGitProviderConfig(providerConfig *models.GitProviderConfig) error { args := m.Called(providerConfig) return args.Error(0) } diff --git a/internal/testing/server/workspaces/mocks/scheduler.go b/internal/testing/server/targets/mocks/scheduler.go similarity index 100% rename from internal/testing/server/workspaces/mocks/scheduler.go rename to internal/testing/server/targets/mocks/scheduler.go diff --git a/internal/testing/server/targets/mocks/workspace_template.go b/internal/testing/server/targets/mocks/workspace_template.go new file mode 100644 index 0000000000..2486c54e47 --- /dev/null +++ b/internal/testing/server/targets/mocks/workspace_template.go @@ -0,0 +1,19 @@ +//go:build testing + +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package mocks + +import ( + "github.com/daytonaio/daytona/pkg/models" +) + +var MockWorkspaceTemplate = models.WorkspaceTemplate{ + BuildConfig: &models.BuildConfig{ + Devcontainer: &models.DevcontainerConfig{ + FilePath: ".devcontainer/devcontainer.json", + }, + }, + RepositoryUrl: "https://github.com/daytonaio/daytona", +} diff --git a/internal/testing/server/targets/mocks/workspace_template_service.go b/internal/testing/server/targets/mocks/workspace_template_service.go new file mode 100644 index 0000000000..6a4024c028 --- /dev/null +++ b/internal/testing/server/targets/mocks/workspace_template_service.go @@ -0,0 +1,82 @@ +//go:build testing + +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package mocks + +import ( + "github.com/daytonaio/daytona/pkg/gitprovider" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/services" + "github.com/daytonaio/daytona/pkg/stores" + "github.com/stretchr/testify/mock" +) + +type mockWorkspaceTemplateService struct { + mock.Mock +} + +func NewMockWorkspaceTemplateService() *mockWorkspaceTemplateService { + return &mockWorkspaceTemplateService{} +} + +func (m *mockWorkspaceTemplateService) Delete(name string, force bool) []error { + args := m.Called(name, force) + return args.Get(0).([]error) +} + +func (m *mockWorkspaceTemplateService) Find(filter *stores.WorkspaceTemplateFilter) (*models.WorkspaceTemplate, error) { + args := m.Called(filter) + return args.Get(0).(*models.WorkspaceTemplate), args.Error(1) +} + +func (m *mockWorkspaceTemplateService) List(filter *stores.WorkspaceTemplateFilter) ([]*models.WorkspaceTemplate, error) { + args := m.Called(filter) + return args.Get(0).([]*models.WorkspaceTemplate), args.Error(1) +} + +func (m *mockWorkspaceTemplateService) SetDefault(name string) error { + args := m.Called(name) + return args.Error(0) +} + +func (m *mockWorkspaceTemplateService) Save(wt *models.WorkspaceTemplate) error { + args := m.Called(wt) + return args.Error(0) +} + +func (m *mockWorkspaceTemplateService) SetPrebuild(workspaceTemplateName string, createPrebuildDto services.CreatePrebuildDTO) (*services.PrebuildDTO, error) { + args := m.Called(workspaceTemplateName, createPrebuildDto) + return args.Get(0).(*services.PrebuildDTO), args.Error(1) +} + +func (m *mockWorkspaceTemplateService) FindPrebuild(workspaceTemplateFilter *stores.WorkspaceTemplateFilter, prebuildFilter *stores.PrebuildFilter) (*services.PrebuildDTO, error) { + args := m.Called(workspaceTemplateFilter, prebuildFilter) + return args.Get(0).(*services.PrebuildDTO), args.Error(1) +} + +func (m *mockWorkspaceTemplateService) ListPrebuilds(workspaceTemplateFilter *stores.WorkspaceTemplateFilter, prebuildFilter *stores.PrebuildFilter) ([]*services.PrebuildDTO, error) { + args := m.Called(workspaceTemplateFilter, prebuildFilter) + return args.Get(0).([]*services.PrebuildDTO), args.Error(1) +} + +func (m *mockWorkspaceTemplateService) DeletePrebuild(workspaceTemplateName string, id string, force bool) []error { + args := m.Called(workspaceTemplateName, id, force) + return args.Get(0).([]error) +} + +func (m *mockWorkspaceTemplateService) StartRetentionPoller() error { + args := m.Called() + return args.Error(0) +} + +func (m *mockWorkspaceTemplateService) EnforceRetentionPolicy() error { + args := m.Called() + return args.Error(0) +} + +func (m *mockWorkspaceTemplateService) ProcessGitEvent(data gitprovider.GitEventData) error { + args := m.Called(data) + return args.Error(0) +} diff --git a/internal/testing/server/targets/store.go b/internal/testing/server/targets/store.go new file mode 100644 index 0000000000..d8e2c36d72 --- /dev/null +++ b/internal/testing/server/targets/store.go @@ -0,0 +1,115 @@ +//go:build testing + +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package targets + +import ( + "context" + "fmt" + + "github.com/daytonaio/daytona/internal/testing/common" + "github.com/daytonaio/daytona/internal/util" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/stores" +) + +type InMemoryTargetStore struct { + common.InMemoryStore + targets map[string]*models.Target + jobStore stores.JobStore +} + +func NewInMemoryTargetStore(jobStore stores.JobStore) stores.TargetStore { + return &InMemoryTargetStore{ + targets: make(map[string]*models.Target), + jobStore: jobStore, + } +} + +func (s *InMemoryTargetStore) List(ctx context.Context, filter *stores.TargetFilter) ([]*models.Target, error) { + return s.processFilters(filter) +} + +func (s *InMemoryTargetStore) Find(ctx context.Context, filter *stores.TargetFilter) (*models.Target, error) { + t, err := s.processFilters(filter) + if err != nil { + return nil, err + } + + if len(t) == 0 { + return nil, stores.ErrTargetNotFound + } + + return t[0], nil +} + +func (s *InMemoryTargetStore) Save(ctx context.Context, target *models.Target) error { + tg := *target + tg.EnvVars = nil + tg.ApiKey = "" + + s.targets[target.Id] = &tg + return nil +} + +func (s *InMemoryTargetStore) Delete(ctx context.Context, target *models.Target) error { + delete(s.targets, target.Id) + return nil +} + +func (s *InMemoryTargetStore) processFilters(filter *stores.TargetFilter) ([]*models.Target, error) { + var result []*models.Target + filteredTargets := make(map[string]*models.Target) + for k, v := range s.targets { + filteredTargets[k] = v + } + + jobs, err := s.jobMap(context.Background()) + if err != nil { + return nil, err + } + + if filter != nil { + if filter.IdOrName != nil { + t, ok := s.targets[*filter.IdOrName] + if ok { + t.LastJob = jobs[t.Id] + return []*models.Target{t}, nil + } else { + return []*models.Target{}, fmt.Errorf("target with id or name %s not found", *filter.IdOrName) + } + } + if filter.Default != nil { + for _, t := range filteredTargets { + if t.IsDefault != *filter.Default { + delete(filteredTargets, t.Name) + } + } + } + } + + for _, t := range filteredTargets { + t.LastJob = jobs[t.Id] + result = append(result, t) + } + + return result, nil +} + +func (s *InMemoryTargetStore) jobMap(ctx context.Context) (map[string]*models.Job, error) { + jobs, err := s.jobStore.List(ctx, &stores.JobFilter{ + ResourceType: util.Pointer(models.ResourceTypeTarget), + }) + if err != nil { + return nil, err + } + + jobMap := make(map[string]*models.Job) + for _, j := range jobs { + jobMap[j.ResourceId] = j + } + + return jobMap, nil +} diff --git a/internal/testing/server/workspaces/metadata_store.go b/internal/testing/server/workspaces/metadata_store.go new file mode 100644 index 0000000000..12844edd44 --- /dev/null +++ b/internal/testing/server/workspaces/metadata_store.go @@ -0,0 +1,43 @@ +//go:build testing + +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package workspaces + +import ( + "context" + + "github.com/daytonaio/daytona/internal/testing/common" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/stores" +) + +type InMemoryWorkspaceMetadataStore struct { + common.InMemoryStore + workspaceMetadataEntries map[string]*models.WorkspaceMetadata +} + +func NewInMemoryWorkspaceMetadataStore() stores.WorkspaceMetadataStore { + return &InMemoryWorkspaceMetadataStore{ + workspaceMetadataEntries: make(map[string]*models.WorkspaceMetadata), + } +} + +func (s *InMemoryWorkspaceMetadataStore) Find(ctx context.Context, workspaceId string) (*models.WorkspaceMetadata, error) { + if _, ok := s.workspaceMetadataEntries[workspaceId]; !ok { + return nil, stores.ErrWorkspaceMetadataNotFound + } + + return s.workspaceMetadataEntries[workspaceId], nil +} + +func (s *InMemoryWorkspaceMetadataStore) Save(ctx context.Context, workspaceMetadata *models.WorkspaceMetadata) error { + s.workspaceMetadataEntries[workspaceMetadata.WorkspaceId] = workspaceMetadata + return nil +} + +func (s *InMemoryWorkspaceMetadataStore) Delete(ctx context.Context, workspaceMetadata *models.WorkspaceMetadata) error { + delete(s.workspaceMetadataEntries, workspaceMetadata.WorkspaceId) + return nil +} diff --git a/internal/testing/server/workspaces/mocks/build_service.go b/internal/testing/server/workspaces/mocks/build_service.go deleted file mode 100644 index 4e91444b0a..0000000000 --- a/internal/testing/server/workspaces/mocks/build_service.go +++ /dev/null @@ -1,58 +0,0 @@ -//go:build testing - -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package mocks - -import ( - "io" - "time" - - "github.com/daytonaio/daytona/pkg/build" - "github.com/daytonaio/daytona/pkg/server/builds/dto" - "github.com/stretchr/testify/mock" -) - -type MockBuildService struct { - mock.Mock -} - -func NewMockBuildService() *MockBuildService { - return &MockBuildService{} -} - -func (m *MockBuildService) Create(createBuildDto dto.BuildCreationData) (string, error) { - args := m.Called(createBuildDto) - return args.String(0), args.Error(1) -} - -func (m *MockBuildService) Find(filter *build.Filter) (*build.Build, error) { - args := m.Called(filter) - return args.Get(0).(*build.Build), args.Error(1) -} - -func (m *MockBuildService) List(filter *build.Filter) ([]*build.Build, error) { - args := m.Called(filter) - return args.Get(0).([]*build.Build), args.Error(1) -} - -func (m *MockBuildService) MarkForDeletion(filter *build.Filter, force bool) []error { - args := m.Called(filter, force) - return args.Get(0).([]error) -} - -func (m *MockBuildService) Delete(id string) error { - args := m.Called(id) - return args.Error(0) -} - -func (m *MockBuildService) AwaitEmptyList(waitTime time.Duration) error { - args := m.Called(waitTime) - return args.Error(0) -} - -func (m *MockBuildService) GetBuildLogReader(buildId string) (io.Reader, error) { - args := m.Called(buildId) - return args.Get(0).(io.Reader), args.Error(1) -} diff --git a/internal/testing/server/workspaces/mocks/container_registry_service.go b/internal/testing/server/workspaces/mocks/container_registry_service.go deleted file mode 100644 index b172c80115..0000000000 --- a/internal/testing/server/workspaces/mocks/container_registry_service.go +++ /dev/null @@ -1,49 +0,0 @@ -//go:build testing - -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package mocks - -import ( - "github.com/daytonaio/daytona/pkg/containerregistry" - "github.com/stretchr/testify/mock" -) - -type mockContainerRegistryService struct { - mock.Mock -} - -func NewMockContainerRegistryService() *mockContainerRegistryService { - return &mockContainerRegistryService{} -} - -func (m *mockContainerRegistryService) Delete(server string) error { - args := m.Called(server) - return args.Error(0) -} - -func (m *mockContainerRegistryService) Find(server string) (*containerregistry.ContainerRegistry, error) { - args := m.Called(server) - return args.Get(0).(*containerregistry.ContainerRegistry), args.Error(1) -} - -func (m *mockContainerRegistryService) FindByImageName(imageName string) (*containerregistry.ContainerRegistry, error) { - args := m.Called(imageName) - return args.Get(0).(*containerregistry.ContainerRegistry), args.Error(1) -} - -func (m *mockContainerRegistryService) List() ([]*containerregistry.ContainerRegistry, error) { - args := m.Called() - return args.Get(0).([]*containerregistry.ContainerRegistry), args.Error(1) -} - -func (m *mockContainerRegistryService) Map() (map[string]*containerregistry.ContainerRegistry, error) { - args := m.Called() - return args.Get(0).(map[string]*containerregistry.ContainerRegistry), args.Error(1) -} - -func (m *mockContainerRegistryService) Save(cr *containerregistry.ContainerRegistry) error { - args := m.Called(cr) - return args.Error(0) -} diff --git a/internal/testing/server/workspaces/mocks/project_config.go b/internal/testing/server/workspaces/mocks/project_config.go deleted file mode 100644 index f6e58ee498..0000000000 --- a/internal/testing/server/workspaces/mocks/project_config.go +++ /dev/null @@ -1,20 +0,0 @@ -//go:build testing - -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package mocks - -import ( - "github.com/daytonaio/daytona/pkg/workspace/project/buildconfig" - "github.com/daytonaio/daytona/pkg/workspace/project/config" -) - -var MockProjectConfig = config.ProjectConfig{ - BuildConfig: &buildconfig.BuildConfig{ - Devcontainer: &buildconfig.DevcontainerConfig{ - FilePath: ".devcontainer/devcontainer.json", - }, - }, - RepositoryUrl: "https://github.com/daytonaio/daytona", -} diff --git a/internal/testing/server/workspaces/mocks/project_config_service.go b/internal/testing/server/workspaces/mocks/project_config_service.go deleted file mode 100644 index 31301edcbf..0000000000 --- a/internal/testing/server/workspaces/mocks/project_config_service.go +++ /dev/null @@ -1,81 +0,0 @@ -//go:build testing - -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package mocks - -import ( - "github.com/daytonaio/daytona/pkg/gitprovider" - "github.com/daytonaio/daytona/pkg/server/projectconfig/dto" - "github.com/daytonaio/daytona/pkg/workspace/project/config" - "github.com/stretchr/testify/mock" -) - -type mockProjectConfigService struct { - mock.Mock -} - -func NewMockProjectConfigService() *mockProjectConfigService { - return &mockProjectConfigService{} -} - -func (m *mockProjectConfigService) Delete(name string, force bool) []error { - args := m.Called(name, force) - return args.Get(0).([]error) -} - -func (m *mockProjectConfigService) Find(filter *config.ProjectConfigFilter) (*config.ProjectConfig, error) { - args := m.Called(filter) - return args.Get(0).(*config.ProjectConfig), args.Error(1) -} - -func (m *mockProjectConfigService) List(filter *config.ProjectConfigFilter) ([]*config.ProjectConfig, error) { - args := m.Called(filter) - return args.Get(0).([]*config.ProjectConfig), args.Error(1) -} - -func (m *mockProjectConfigService) SetDefault(name string) error { - args := m.Called(name) - return args.Error(0) -} - -func (m *mockProjectConfigService) Save(pc *config.ProjectConfig) error { - args := m.Called(pc) - return args.Error(0) -} - -func (m *mockProjectConfigService) SetPrebuild(projectConfigName string, createProjectDto dto.CreatePrebuildDTO) (*dto.PrebuildDTO, error) { - args := m.Called(projectConfigName, createProjectDto) - return args.Get(0).(*dto.PrebuildDTO), args.Error(1) -} - -func (m *mockProjectConfigService) FindPrebuild(projectConfigFilter *config.ProjectConfigFilter, prebuildFilter *config.PrebuildFilter) (*dto.PrebuildDTO, error) { - args := m.Called(projectConfigFilter, prebuildFilter) - return args.Get(0).(*dto.PrebuildDTO), args.Error(1) -} - -func (m *mockProjectConfigService) ListPrebuilds(projectConfigFilter *config.ProjectConfigFilter, prebuildFilter *config.PrebuildFilter) ([]*dto.PrebuildDTO, error) { - args := m.Called(projectConfigFilter, prebuildFilter) - return args.Get(0).([]*dto.PrebuildDTO), args.Error(1) -} - -func (m *mockProjectConfigService) DeletePrebuild(projectConfigName string, id string, force bool) []error { - args := m.Called(projectConfigName, id, force) - return args.Get(0).([]error) -} - -func (m *mockProjectConfigService) StartRetentionPoller() error { - args := m.Called() - return args.Error(0) -} - -func (m *mockProjectConfigService) EnforceRetentionPolicy() error { - args := m.Called() - return args.Error(0) -} - -func (m *mockProjectConfigService) ProcessGitEvent(data gitprovider.GitEventData) error { - args := m.Called(data) - return args.Error(0) -} diff --git a/internal/testing/server/workspaces/mocks/provisioner.go b/internal/testing/server/workspaces/mocks/provisioner.go deleted file mode 100644 index 11e84f7640..0000000000 --- a/internal/testing/server/workspaces/mocks/provisioner.go +++ /dev/null @@ -1,69 +0,0 @@ -//go:build testing - -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package mocks - -import ( - "context" - - "github.com/daytonaio/daytona/pkg/provider" - "github.com/daytonaio/daytona/pkg/provisioner" - "github.com/daytonaio/daytona/pkg/workspace" - "github.com/daytonaio/daytona/pkg/workspace/project" - "github.com/stretchr/testify/mock" -) - -type mockProvisioner struct { - mock.Mock -} - -func NewMockProvisioner() *mockProvisioner { - return &mockProvisioner{} -} - -func (p *mockProvisioner) CreateProject(params provisioner.ProjectParams) error { - args := p.Called(params) - return args.Error(0) -} - -func (p *mockProvisioner) CreateWorkspace(workspace *workspace.Workspace, target *provider.ProviderTarget) error { - args := p.Called(workspace, target) - return args.Error(0) -} - -func (p *mockProvisioner) DestroyProject(proj *project.Project, target *provider.ProviderTarget) error { - args := p.Called(proj, target) - return args.Error(0) -} - -func (p *mockProvisioner) DestroyWorkspace(workspace *workspace.Workspace, target *provider.ProviderTarget) error { - args := p.Called(workspace, target) - return args.Error(0) -} - -func (p *mockProvisioner) GetWorkspaceInfo(ctx context.Context, w *workspace.Workspace, target *provider.ProviderTarget) (*workspace.WorkspaceInfo, error) { - args := p.Called(ctx, w, target) - return args.Get(0).(*workspace.WorkspaceInfo), args.Error(1) -} - -func (p *mockProvisioner) StartProject(params provisioner.ProjectParams) error { - args := p.Called(params) - return args.Error(0) -} - -func (p *mockProvisioner) StartWorkspace(workspace *workspace.Workspace, target *provider.ProviderTarget) error { - args := p.Called(workspace, target) - return args.Error(0) -} - -func (p *mockProvisioner) StopProject(proj *project.Project, target *provider.ProviderTarget) error { - args := p.Called(proj, target) - return args.Error(0) -} - -func (p *mockProvisioner) StopWorkspace(workspace *workspace.Workspace, target *provider.ProviderTarget) error { - args := p.Called(workspace, target) - return args.Error(0) -} diff --git a/internal/testing/server/workspaces/store.go b/internal/testing/server/workspaces/store.go index ca31f0e8bc..5cb67652b6 100644 --- a/internal/testing/server/workspaces/store.go +++ b/internal/testing/server/workspaces/store.go @@ -6,48 +6,85 @@ package workspaces import ( - "github.com/daytonaio/daytona/pkg/workspace" + "context" + + "github.com/daytonaio/daytona/internal/testing/common" + "github.com/daytonaio/daytona/internal/util" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/stores" ) type InMemoryWorkspaceStore struct { - workspaces map[string]*workspace.Workspace + common.InMemoryStore + jobStore stores.JobStore + workspaces map[string]*models.Workspace } -func NewInMemoryWorkspaceStore() workspace.Store { +func NewInMemoryWorkspaceStore(jobStore stores.JobStore) stores.WorkspaceStore { return &InMemoryWorkspaceStore{ - workspaces: make(map[string]*workspace.Workspace), + workspaces: make(map[string]*models.Workspace), + jobStore: jobStore, } } -func (s *InMemoryWorkspaceStore) List() ([]*workspace.Workspace, error) { - workspaces := []*workspace.Workspace{} +func (s *InMemoryWorkspaceStore) List(ctx context.Context) ([]*models.Workspace, error) { + workspaces := []*models.Workspace{} + jobs, err := s.jobMap(ctx) + if err != nil { + return nil, err + } + for _, w := range s.workspaces { + w.LastJob = jobs[w.Id] workspaces = append(workspaces, w) } return workspaces, nil } -func (s *InMemoryWorkspaceStore) Find(idOrName string) (*workspace.Workspace, error) { - ws, ok := s.workspaces[idOrName] +func (s *InMemoryWorkspaceStore) Find(ctx context.Context, idOrName string) (*models.Workspace, error) { + jobs, err := s.jobMap(ctx) + if err != nil { + return nil, err + } + + w, ok := s.workspaces[idOrName] if !ok { for _, w := range s.workspaces { if w.Name == idOrName { + w.LastJob = jobs[w.Id] return w, nil } } - return nil, workspace.ErrWorkspaceNotFound + return nil, stores.ErrWorkspaceNotFound } + w.LastJob = jobs[w.Id] - return ws, nil + return w, nil } -func (s *InMemoryWorkspaceStore) Save(workspace *workspace.Workspace) error { +func (s *InMemoryWorkspaceStore) Save(ctx context.Context, workspace *models.Workspace) error { s.workspaces[workspace.Id] = workspace return nil } -func (s *InMemoryWorkspaceStore) Delete(workspace *workspace.Workspace) error { +func (s *InMemoryWorkspaceStore) Delete(ctx context.Context, workspace *models.Workspace) error { delete(s.workspaces, workspace.Id) return nil } + +func (s *InMemoryWorkspaceStore) jobMap(ctx context.Context) (map[string]*models.Job, error) { + jobs, err := s.jobStore.List(ctx, &stores.JobFilter{ + ResourceType: util.Pointer(models.ResourceTypeWorkspace), + }) + if err != nil { + return nil, err + } + + jobMap := make(map[string]*models.Job) + for _, j := range jobs { + jobMap[j.ResourceId] = j + } + + return jobMap, nil +} diff --git a/internal/testing/server/workspacetemplate/store.go b/internal/testing/server/workspacetemplate/store.go new file mode 100644 index 0000000000..e3de26e4a6 --- /dev/null +++ b/internal/testing/server/workspacetemplate/store.go @@ -0,0 +1,98 @@ +//go:build testing + +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package workspacetemplate + +import ( + "context" + "fmt" + + "github.com/daytonaio/daytona/internal/testing/common" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/stores" +) + +type InMemoryWorkspaceTemplateStore struct { + common.InMemoryStore + workspaceTemplates map[string]*models.WorkspaceTemplate +} + +func NewInMemoryWorkspaceTemplateStore() stores.WorkspaceTemplateStore { + return &InMemoryWorkspaceTemplateStore{ + workspaceTemplates: make(map[string]*models.WorkspaceTemplate), + } +} + +func (s *InMemoryWorkspaceTemplateStore) List(ctx context.Context, filter *stores.WorkspaceTemplateFilter) ([]*models.WorkspaceTemplate, error) { + return s.processFilters(filter) +} + +func (s *InMemoryWorkspaceTemplateStore) Find(ctx context.Context, filter *stores.WorkspaceTemplateFilter) (*models.WorkspaceTemplate, error) { + workspaceTemplates, err := s.processFilters(filter) + if err != nil { + return nil, err + } + if len(workspaceTemplates) == 0 { + return nil, stores.ErrWorkspaceTemplateNotFound + } + + return workspaceTemplates[0], nil +} + +func (s *InMemoryWorkspaceTemplateStore) Save(ctx context.Context, workspaceTemplate *models.WorkspaceTemplate) error { + s.workspaceTemplates[workspaceTemplate.Name] = workspaceTemplate + return nil +} + +func (s *InMemoryWorkspaceTemplateStore) Delete(ctx context.Context, workspaceTemplate *models.WorkspaceTemplate) error { + delete(s.workspaceTemplates, workspaceTemplate.Name) + return nil +} + +func (s *InMemoryWorkspaceTemplateStore) processFilters(filter *stores.WorkspaceTemplateFilter) ([]*models.WorkspaceTemplate, error) { + var result []*models.WorkspaceTemplate + filteredWorkspaceTemplates := make(map[string]*models.WorkspaceTemplate) + for k, v := range s.workspaceTemplates { + filteredWorkspaceTemplates[k] = v + } + + if filter != nil { + if filter.Name != nil { + workspaceTemplate, ok := s.workspaceTemplates[*filter.Name] + if ok { + return []*models.WorkspaceTemplate{workspaceTemplate}, nil + } else { + return []*models.WorkspaceTemplate{}, fmt.Errorf("workspace template with name %s not found", *filter.Name) + } + } + if filter.Url != nil { + for _, workspaceTemplate := range filteredWorkspaceTemplates { + if workspaceTemplate.RepositoryUrl != *filter.Url { + delete(filteredWorkspaceTemplates, workspaceTemplate.Name) + } + } + } + if filter.Default != nil { + for _, workspaceTemplate := range filteredWorkspaceTemplates { + if workspaceTemplate.IsDefault != *filter.Default { + delete(filteredWorkspaceTemplates, workspaceTemplate.Name) + } + } + } + if filter.GitProviderConfigId != nil { + for _, workspaceTemplate := range filteredWorkspaceTemplates { + if workspaceTemplate.GitProviderConfigId != nil && *workspaceTemplate.GitProviderConfigId != *filter.GitProviderConfigId { + delete(filteredWorkspaceTemplates, workspaceTemplate.Name) + } + } + } + } + + for _, workspaceTemplate := range filteredWorkspaceTemplates { + result = append(result, workspaceTemplate) + } + + return result, nil +} diff --git a/internal/util/apiclient/api_client.go b/internal/util/apiclient/api_client.go index 937dc7684f..7426b327b5 100644 --- a/internal/util/apiclient/api_client.go +++ b/internal/util/apiclient/api_client.go @@ -5,7 +5,6 @@ package apiclient import ( "context" - "errors" "fmt" "net/http" "net/url" @@ -14,6 +13,7 @@ import ( "github.com/daytonaio/daytona/internal" "github.com/daytonaio/daytona/internal/constants" "github.com/daytonaio/daytona/pkg/apiclient" + "github.com/daytonaio/daytona/pkg/common" "github.com/daytonaio/daytona/pkg/telemetry" ) @@ -61,8 +61,9 @@ func GetApiClient(profile *config.Profile) (*apiclient.APIClient, error) { clientConfig.AddDefaultHeader(telemetry.ENABLED_HEADER, "true") clientConfig.AddDefaultHeader(telemetry.SESSION_ID_HEADER, internal.SESSION_ID) clientConfig.AddDefaultHeader(telemetry.CLIENT_ID_HEADER, config.GetClientId()) - if internal.WorkspaceMode() { - clientConfig.AddDefaultHeader(telemetry.SOURCE_HEADER, string(telemetry.CLI_PROJECT_SOURCE)) + + if common.AgentMode() { + clientConfig.AddDefaultHeader(telemetry.SOURCE_HEADER, string(telemetry.CLI_AGENT_MODE_SOURCE)) } else { clientConfig.AddDefaultHeader(telemetry.SOURCE_HEADER, string(telemetry.CLI_SOURCE)) } @@ -88,6 +89,33 @@ func GetApiClient(profile *config.Profile) (*apiclient.APIClient, error) { return apiClient, nil } +func GetRunnerApiClient(apiUrl, apiKey, clientId string, telemetryEnabled bool) (*apiclient.APIClient, error) { + clientConfig := apiclient.NewConfiguration() + clientConfig.Servers = apiclient.ServerConfigurations{ + { + URL: apiUrl, + }, + } + + clientConfig.AddDefaultHeader("Authorization", fmt.Sprintf("Bearer %s", apiKey)) + clientConfig.AddDefaultHeader(CLIENT_VERSION_HEADER, internal.Version) + + if telemetryEnabled { + clientConfig.AddDefaultHeader(telemetry.ENABLED_HEADER, "true") + clientConfig.AddDefaultHeader(telemetry.SESSION_ID_HEADER, internal.SESSION_ID) + clientConfig.AddDefaultHeader(telemetry.CLIENT_ID_HEADER, clientId) + clientConfig.AddDefaultHeader(telemetry.SOURCE_HEADER, string(telemetry.RUNNER_SOURCE)) + } + + apiClient = apiclient.NewAPIClient(clientConfig) + + apiClient.GetConfig().HTTPClient = &http.Client{ + Transport: http.DefaultTransport, + } + + return apiClient, nil +} + func GetAgentApiClient(apiUrl, apiKey, clientId string, telemetryEnabled bool) (*apiclient.APIClient, error) { clientConfig := apiclient.NewConfiguration() clientConfig.Servers = apiclient.ServerConfigurations{ @@ -115,48 +143,34 @@ func GetAgentApiClient(apiUrl, apiKey, clientId string, telemetryEnabled bool) ( return apiClient, nil } -func GetWorkspace(workspaceNameOrId string, verbose bool) (*apiclient.WorkspaceDTO, error) { +func GetTarget(targetNameOrId string) (*apiclient.TargetDTO, int, error) { ctx := context.Background() apiClient, err := GetApiClient(nil) if err != nil { - return nil, err + return nil, -1, err } - workspace, res, err := apiClient.WorkspaceAPI.GetWorkspace(ctx, workspaceNameOrId).Verbose(verbose).Execute() + target, res, err := apiClient.TargetAPI.FindTarget(ctx, targetNameOrId).Execute() if err != nil { - return nil, HandleErrorResponse(res, err) + return nil, res.StatusCode, HandleErrorResponse(res, err) } - return workspace, nil + return target, res.StatusCode, nil } -func GetFirstWorkspaceProjectName(workspaceId string, projectName string, profile *config.Profile) (string, error) { +func GetWorkspace(workspaceNameOrId string) (*apiclient.WorkspaceDTO, int, error) { ctx := context.Background() - apiClient, err := GetApiClient(profile) + apiClient, err := GetApiClient(nil) if err != nil { - return "", err + return nil, -1, err } - wsInfo, res, err := apiClient.WorkspaceAPI.GetWorkspace(ctx, workspaceId).Execute() + workspace, res, err := apiClient.WorkspaceAPI.FindWorkspace(ctx, workspaceNameOrId).Execute() if err != nil { - return "", HandleErrorResponse(res, err) - } - - if projectName == "" { - if len(wsInfo.Projects) == 0 { - return "", errors.New("no projects found in workspace") - } - - return wsInfo.Projects[0].Name, nil - } - - for _, project := range wsInfo.Projects { - if project.Name == projectName { - return project.Name, nil - } + return nil, res.StatusCode, HandleErrorResponse(res, err) } - return "", errors.New("project not found in workspace") + return workspace, res.StatusCode, nil } diff --git a/internal/util/apiclient/conversion/conversion.go b/internal/util/apiclient/conversion/conversion.go new file mode 100644 index 0000000000..3c37079563 --- /dev/null +++ b/internal/util/apiclient/conversion/conversion.go @@ -0,0 +1,26 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package conversion + +import ( + "encoding/json" +) + +func Convert[F any, T any](from *F) (*T, error) { + if from == nil { + return nil, nil + } + + fromBytes, err := json.Marshal(from) + if err != nil { + return nil, err + } + + var to T + err = json.Unmarshal(fromBytes, &to) + if err != nil { + return nil, err + } + return &to, nil +} diff --git a/internal/util/apiclient/conversion/project.go b/internal/util/apiclient/conversion/project.go deleted file mode 100644 index db1283b6d7..0000000000 --- a/internal/util/apiclient/conversion/project.go +++ /dev/null @@ -1,207 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package conversion - -import ( - "github.com/daytonaio/daytona/pkg/apiclient" - "github.com/daytonaio/daytona/pkg/gitprovider" - pc_dto "github.com/daytonaio/daytona/pkg/server/projectconfig/dto" - project_dto "github.com/daytonaio/daytona/pkg/server/workspaces/dto" - "github.com/daytonaio/daytona/pkg/workspace/project" - "github.com/daytonaio/daytona/pkg/workspace/project/buildconfig" - "github.com/daytonaio/daytona/pkg/workspace/project/config" -) - -func ToProject(projectDTO *apiclient.Project) *project.Project { - if projectDTO == nil { - return nil - } - - repository := &gitprovider.GitRepository{ - Id: projectDTO.Repository.Id, - Name: projectDTO.Repository.Name, - Branch: projectDTO.Repository.Branch, - Owner: projectDTO.Repository.Owner, - Path: projectDTO.Repository.Path, - Sha: projectDTO.Repository.Sha, - Source: projectDTO.Repository.Source, - Url: projectDTO.Repository.Url, - } - - var projectState *project.ProjectState - if projectDTO.State != nil { - uptime := projectDTO.State.Uptime - projectState = &project.ProjectState{ - UpdatedAt: projectDTO.State.UpdatedAt, - Uptime: uint64(uptime), - GitStatus: ToGitStatus(projectDTO.State.GitStatus), - } - } - - var projectBuild *buildconfig.BuildConfig - if projectDTO.BuildConfig != nil { - projectBuild = &buildconfig.BuildConfig{} - if projectDTO.BuildConfig.Devcontainer != nil { - projectBuild.Devcontainer = &buildconfig.DevcontainerConfig{ - FilePath: projectDTO.BuildConfig.Devcontainer.FilePath, - } - } - } - - project := &project.Project{ - Name: projectDTO.Name, - Image: projectDTO.Image, - User: projectDTO.User, - BuildConfig: projectBuild, - Repository: repository, - Target: projectDTO.Target, - WorkspaceId: projectDTO.WorkspaceId, - State: projectState, - GitProviderConfigId: projectDTO.GitProviderConfigId, - } - - if projectDTO.Repository.PrNumber != nil { - prNumber := uint32(*projectDTO.Repository.PrNumber) - project.Repository.PrNumber = &prNumber - } - - return project -} - -func ToGitStatus(gitStatusDTO *apiclient.GitStatus) *project.GitStatus { - if gitStatusDTO == nil { - return nil - } - - files := []*project.FileStatus{} - for _, fileDTO := range gitStatusDTO.FileStatus { - staging := project.Status(string(fileDTO.Staging)) - worktree := project.Status(string(fileDTO.Worktree)) - file := &project.FileStatus{ - Name: fileDTO.Name, - Extra: fileDTO.Extra, - Staging: staging, - Worktree: worktree, - } - files = append(files, file) - } - - var ahead, behind int - if gitStatusDTO.Ahead != nil { - ahead = int(*gitStatusDTO.Ahead) - } - if gitStatusDTO.Behind != nil { - behind = int(*gitStatusDTO.Behind) - } - - var branchPublished bool - if gitStatusDTO.BranchPublished != nil { - branchPublished = *gitStatusDTO.BranchPublished - } - - return &project.GitStatus{ - CurrentBranch: gitStatusDTO.CurrentBranch, - Files: files, - BranchPublished: branchPublished, - Ahead: ahead, - Behind: behind, - } -} - -func ToGitStatusDTO(gitStatus *project.GitStatus) *apiclient.GitStatus { - if gitStatus == nil { - return nil - } - - fileStatusDTO := []apiclient.FileStatus{} - for _, file := range gitStatus.Files { - staging := apiclient.Status(string(file.Staging)) - worktree := apiclient.Status(string(file.Worktree)) - fileDTO := apiclient.FileStatus{ - Name: file.Name, - Extra: file.Extra, - Staging: staging, - Worktree: worktree, - } - fileStatusDTO = append(fileStatusDTO, fileDTO) - } - - var ahead, behind *int32 - if gitStatus.Ahead != 0 { - value := int32(gitStatus.Ahead) - ahead = &value - } - if gitStatus.Behind != 0 { - value := int32(gitStatus.Behind) - behind = &value - } - var branchPublished *bool - if gitStatus.BranchPublished { - value := true - branchPublished = &value - } - - return &apiclient.GitStatus{ - CurrentBranch: gitStatus.CurrentBranch, - FileStatus: fileStatusDTO, - BranchPublished: branchPublished, - Ahead: ahead, - Behind: behind, - } -} - -func ToProjectConfig(createProjectConfigDto pc_dto.CreateProjectConfigDTO) *config.ProjectConfig { - result := &config.ProjectConfig{ - Name: createProjectConfigDto.Name, - BuildConfig: createProjectConfigDto.BuildConfig, - EnvVars: createProjectConfigDto.EnvVars, - GitProviderConfigId: createProjectConfigDto.GitProviderConfigId, - } - - result.RepositoryUrl = createProjectConfigDto.RepositoryUrl - - if createProjectConfigDto.Image != nil { - result.Image = *createProjectConfigDto.Image - } - - if createProjectConfigDto.User != nil { - result.User = *createProjectConfigDto.User - } - - return result -} - -func CreateDtoToProject(createProjectDto project_dto.CreateProjectDTO) *project.Project { - p := &project.Project{ - Name: createProjectDto.Name, - BuildConfig: createProjectDto.BuildConfig, - Repository: createProjectDto.Source.Repository, - EnvVars: createProjectDto.EnvVars, - GitProviderConfigId: createProjectDto.GitProviderConfigId, - } - - if createProjectDto.Image != nil { - p.Image = *createProjectDto.Image - } - - if createProjectDto.User != nil { - p.User = *createProjectDto.User - } - - return p -} - -func CreateConfigDtoToProject(createProjectConfigDto pc_dto.CreateProjectConfigDTO) *project.Project { - return &project.Project{ - Name: createProjectConfigDto.Name, - Image: *createProjectConfigDto.Image, - User: *createProjectConfigDto.User, - BuildConfig: createProjectConfigDto.BuildConfig, - GitProviderConfigId: createProjectConfigDto.GitProviderConfigId, - Repository: &gitprovider.GitRepository{ - Url: createProjectConfigDto.RepositoryUrl, - }, - EnvVars: createProjectConfigDto.EnvVars, - } -} diff --git a/internal/util/apiclient/conversion/target.go b/internal/util/apiclient/conversion/target.go deleted file mode 100644 index 2ad2ba2f33..0000000000 --- a/internal/util/apiclient/conversion/target.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package conversion - -import ( - "github.com/daytonaio/daytona/pkg/provider" - "github.com/daytonaio/daytona/pkg/server/providertargets/dto" -) - -func ToProviderTarget(createProviderTargetDto dto.CreateProviderTargetDTO) *provider.ProviderTarget { - return &provider.ProviderTarget{ - Name: createProviderTargetDto.Name, - ProviderInfo: createProviderTargetDto.ProviderInfo, - Options: createProviderTargetDto.Options, - } -} diff --git a/internal/util/apiclient/websocket_log_reader.go b/internal/util/apiclient/websocket_log_reader.go deleted file mode 100644 index c60ddf07ff..0000000000 --- a/internal/util/apiclient/websocket_log_reader.go +++ /dev/null @@ -1,155 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package apiclient - -import ( - "context" - "fmt" - "sync" - "time" - - "github.com/daytonaio/daytona/cmd/daytona/config" - "github.com/daytonaio/daytona/pkg/logs" - logs_view "github.com/daytonaio/daytona/pkg/views/logs" - "github.com/gorilla/websocket" - log "github.com/sirupsen/logrus" -) - -var workspaceLogsStarted bool - -func ReadWorkspaceLogs(ctx context.Context, activeProfile config.Profile, workspaceId string, projectNames []string, follow, showWorkspaceLogs bool, from *time.Time) { - var wg sync.WaitGroup - query := "" - if follow { - query = "follow=true" - } - - if !showWorkspaceLogs { - workspaceLogsStarted = true - } - logs_view.CalculateLongestPrefixLength(projectNames) - - for index, projectName := range projectNames { - wg.Add(1) - go func(projectName string, from *time.Time) { - defer wg.Done() - - for { - // Make sure workspace logs started before showing any project logs - if !workspaceLogsStarted { - time.Sleep(250 * time.Millisecond) - continue - } - - ws, res, err := GetWebsocketConn(ctx, fmt.Sprintf("/log/workspace/%s/%s", workspaceId, projectName), &activeProfile, &query) - // We want to retry getting the logs if it fails - if err != nil { - log.Trace(HandleErrorResponse(res, err)) - time.Sleep(500 * time.Millisecond) - continue - } - - readJSONLog(ctx, ws, index, from) - ws.Close() - break - } - }(projectName, from) - } - - if showWorkspaceLogs { - for { - ws, res, err := GetWebsocketConn(ctx, fmt.Sprintf("/log/workspace/%s", workspaceId), &activeProfile, &query) - // We want to retry getting the logs if it fails - if err != nil { - log.Trace(HandleErrorResponse(res, err)) - time.Sleep(250 * time.Millisecond) - continue - } - - readJSONLog(ctx, ws, logs_view.STATIC_INDEX, from) - ws.Close() - break - } - } - - wg.Wait() -} - -func ReadBuildLogs(ctx context.Context, activeProfile config.Profile, buildId string, query string) { - logs_view.CalculateLongestPrefixLength([]string{buildId}) - - for { - ws, res, err := GetWebsocketConn(ctx, fmt.Sprintf("/log/build/%s", buildId), &activeProfile, &query) - // We want to retry getting the logs if it fails - if err != nil { - log.Trace(HandleErrorResponse(res, err)) - time.Sleep(250 * time.Millisecond) - continue - } - - readJSONLog(ctx, ws, logs_view.FIRST_PROJECT_INDEX, nil) - ws.Close() - break - } -} - -func readJSONLog(ctx context.Context, ws *websocket.Conn, index int, from *time.Time) { - logEntriesChan := make(chan logs.LogEntry) - readErr := make(chan error) - go func() { - for { - var logEntry logs.LogEntry - - err := ws.ReadJSON(&logEntry) - - // An empty entry will be sent from the server on close/EOF - // We don't want to print that - if logEntry != (logs.LogEntry{}) { - logEntriesChan <- logEntry - } - - if err != nil { - if websocket.IsUnexpectedCloseError(err, websocket.CloseNormalClosure) { - log.Error(err) - } - readErr <- err - return - } - } - }() - - for { - select { - case <-ctx.Done(): - return - case logEntry := <-logEntriesChan: - if from != nil { - parsedTime, err := time.Parse(time.RFC3339Nano, logEntry.Time) - if err != nil { - log.Trace(err) - } - - if parsedTime.After(*from) || parsedTime.Equal(*from) { - logs_view.DisplayLogEntry(logEntry, index) - } - } else { - logs_view.DisplayLogEntry(logEntry, index) - } - - case err := <-readErr: - if err != nil { - err := ws.WriteControl(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""), time.Now().Add(time.Second)) - if err != nil { - log.Trace(err) - } - ws.Close() - return - } - } - - if !workspaceLogsStarted && index == logs_view.STATIC_INDEX { - workspaceLogsStarted = true - } - } -} diff --git a/internal/util/cmd.go b/internal/util/cmd.go index fa0868ee7c..6fb29228e7 100644 --- a/internal/util/cmd.go +++ b/internal/util/cmd.go @@ -4,7 +4,8 @@ package util const ( - WORKSPACE_GROUP = "workspace" - SERVER_GROUP = "server" - PROFILE_GROUP = "profile" + TARGET_GROUP = "target" + SERVER_GROUP = "server" + PROFILE_GROUP = "profile" + RUNNER_GROUP = "runner" ) diff --git a/internal/util/config.go b/internal/util/config.go new file mode 100644 index 0000000000..dbeb49e2c6 --- /dev/null +++ b/internal/util/config.go @@ -0,0 +1,14 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package util + +import "os" + +func DirectoryValidator(path *string) error { + _, err := os.Stat(*path) + if os.IsNotExist(err) { + return os.MkdirAll(*path, 0700) + } + return err +} diff --git a/internal/util/deleted_name.go b/internal/util/deleted_name.go new file mode 100644 index 0000000000..ce3de9aceb --- /dev/null +++ b/internal/util/deleted_name.go @@ -0,0 +1,14 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package util + +import ( + "fmt" + + "github.com/daytonaio/daytona/internal/constants" +) + +func AddDeletedToName(name string) string { + return fmt.Sprintf("%s%s%s", constants.DELETED_CIRCUMFIX, name, constants.DELETED_CIRCUMFIX) +} diff --git a/internal/util/log_formatter.go b/internal/util/log_formatter.go new file mode 100644 index 0000000000..7b215807da --- /dev/null +++ b/internal/util/log_formatter.go @@ -0,0 +1,33 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package util + +import ( + "io" + + log "github.com/sirupsen/logrus" +) + +type LogFormatter struct { + TextFormatter *log.TextFormatter + ProcessLogWriter io.Writer +} + +func (f *LogFormatter) Format(entry *log.Entry) ([]byte, error) { + formatted, err := f.TextFormatter.Format(entry) + if err != nil { + return nil, err + } + + if f.ProcessLogWriter != nil { + _, err = f.ProcessLogWriter.Write(formatted) + if err != nil { + return nil, err + } + } + + // Return the original message without log decoration + // We don't want decoration to show up in the target creation logs + return []byte(entry.Message + "\n"), nil +} diff --git a/internal/util/path.go b/internal/util/path.go index 482cf6075e..7213b40b6a 100644 --- a/internal/util/path.go +++ b/internal/util/path.go @@ -11,15 +11,15 @@ import ( "github.com/daytonaio/daytona/cmd/daytona/config" ) -func GetHomeDir(activeProfile config.Profile, workspaceId string, projectName string, gpgKey string) (string, error) { - err := config.EnsureSshConfigEntryAdded(activeProfile.Id, workspaceId, projectName, gpgKey) +func GetHomeDir(activeProfile config.Profile, workspaceId string, gpgKey *string) (string, error) { + err := config.EnsureSshConfigEntryAdded(activeProfile.Id, workspaceId, gpgKey) if err != nil { return "", err } - projectHostname := config.GetProjectHostname(activeProfile.Id, workspaceId, projectName) + workspaceHostname := config.GetHostname(activeProfile.Id, workspaceId) - homeDir, err := exec.Command("ssh", projectHostname, "echo", "$HOME").Output() + homeDir, err := exec.Command("ssh", workspaceHostname, "echo", "$HOME").Output() if err != nil { return "", err } @@ -27,27 +27,27 @@ func GetHomeDir(activeProfile config.Profile, workspaceId string, projectName st return strings.TrimRight(string(homeDir), "\n"), nil } -func GetProjectDir(activeProfile config.Profile, workspaceId string, projectName string, gpgKey string) (string, error) { - err := config.EnsureSshConfigEntryAdded(activeProfile.Id, workspaceId, projectName, gpgKey) +func GetWorkspaceDir(activeProfile config.Profile, workspaceId string, gpgKey *string) (string, error) { + err := config.EnsureSshConfigEntryAdded(activeProfile.Id, workspaceId, gpgKey) if err != nil { return "", err } - projectHostname := config.GetProjectHostname(activeProfile.Id, workspaceId, projectName) + workspaceHostname := config.GetHostname(activeProfile.Id, workspaceId) - daytonaProjectDir, err := exec.Command("ssh", projectHostname, "echo", "$DAYTONA_PROJECT_DIR").Output() + daytonaWorkspaceDir, err := exec.Command("ssh", workspaceHostname, "echo", "$DAYTONA_WORKSPACE_DIR").Output() if err != nil { return "", err } - if strings.TrimRight(string(daytonaProjectDir), "\n") != "" { - return strings.TrimRight(string(daytonaProjectDir), "\n"), nil + if strings.TrimRight(string(daytonaWorkspaceDir), "\n") != "" { + return strings.TrimRight(string(daytonaWorkspaceDir), "\n"), nil } - homeDir, err := GetHomeDir(activeProfile, workspaceId, projectName, gpgKey) + homeDir, err := GetHomeDir(activeProfile, workspaceId, gpgKey) if err != nil { return "", err } - return path.Join(homeDir, projectName), nil + return path.Join(homeDir, workspaceId), nil } diff --git a/internal/util/pointer.go b/internal/util/pointer.go deleted file mode 100644 index 31aa816a6d..0000000000 --- a/internal/util/pointer.go +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package util - -// Use generics to create a pointer to a value -func Pointer[T any](d T) *T { - return &d -} diff --git a/internal/util/time.go b/internal/util/time.go index 399b7d19e0..6c0d73fb16 100644 --- a/internal/util/time.go +++ b/internal/util/time.go @@ -45,24 +45,24 @@ func FormatUptime(uptime int32) string { duration := time.Duration(uptime) * time.Second if duration < time.Minute { - return "< 1 minute" + return "< 1 minute ago" } else if duration < time.Hour { minutes := int(duration.Minutes()) if minutes == 1 { - return "1 minute" + return "1 minute ago" } - return fmt.Sprintf("%d minutes", minutes) + return fmt.Sprintf("%d minutes ago", minutes) } else if duration < 24*time.Hour { hours := int(duration.Hours()) if hours == 1 { - return "1 hour" + return "1 hour ago" } - return fmt.Sprintf("%d hours", hours) + return fmt.Sprintf("%d hours ago", hours) } else { days := int(duration.Hours() / 24) if days == 1 { - return "1 day" + return "1 day ago" } - return fmt.Sprintf("%d days", days) + return fmt.Sprintf("%d days ago", days) } } diff --git a/internal/util/map.go b/internal/util/types.go similarity index 50% rename from internal/util/map.go rename to internal/util/types.go index ce92c0052f..15a633c6f2 100644 --- a/internal/util/map.go +++ b/internal/util/types.go @@ -3,6 +3,11 @@ package util +// Use generics to create a pointer to a value +func Pointer[T any](d T) *T { + return &d +} + func ArrayMap[T, U any](data []T, f func(T) U) []U { res := make([]U, 0, len(data)) @@ -12,3 +17,11 @@ func ArrayMap[T, U any](data []T, f func(T) U) []U { return res } + +func StringsToInterface(slice []string) []interface{} { + args := make([]interface{}, len(slice)) + for i, v := range slice { + args[i] = v + } + return args +} diff --git a/internal/util/apiclient/websocket_conn.go b/internal/util/websocket_conn.go similarity index 57% rename from internal/util/apiclient/websocket_conn.go rename to internal/util/websocket_conn.go index 417d4d9cb4..421f3fab09 100644 --- a/internal/util/apiclient/websocket_conn.go +++ b/internal/util/websocket_conn.go @@ -1,7 +1,7 @@ // Copyright 2024 Daytona Platforms Inc. // SPDX-License-Identifier: Apache-2.0 -package apiclient +package util import ( "context" @@ -11,39 +11,16 @@ import ( "net/url" "regexp" - "github.com/daytonaio/daytona/cmd/daytona/config" "github.com/gorilla/websocket" ) -func GetWebsocketConn(ctx context.Context, path string, profile *config.Profile, query *string) (*websocket.Conn, *http.Response, error) { - c, err := config.GetConfig() - if err != nil { - return nil, nil, err - } - - var serverUrl string - var apiKey string - - var activeProfile config.Profile - if profile == nil { - var err error - activeProfile, err = c.GetActiveProfile() - if err != nil { - return nil, nil, err - } - } else { - activeProfile = *profile - } - - serverUrl = activeProfile.Api.Url - apiKey = activeProfile.Api.Key - +func GetWebsocketConn(ctx context.Context, path string, serverUrl string, apiKey string, query *string) (*websocket.Conn, *http.Response, error) { url, err := url.JoinPath(serverUrl, path) if err != nil { return nil, nil, err } - wsUrl, err := GetWebSocketUrl(url) + wsUrl, err := getWebSocketUrl(url) if err != nil { return nil, nil, err } @@ -57,7 +34,7 @@ func GetWebsocketConn(ctx context.Context, path string, profile *config.Profile, }) } -func GetWebSocketUrl(apiUrl string) (string, error) { +func getWebSocketUrl(apiUrl string) (string, error) { hostRegex := regexp.MustCompile(`(https*)://(.*)`) matches := hostRegex.FindStringSubmatch(apiUrl) diff --git a/pkg/agent/agent.go b/pkg/agent/agent.go index efb0bdcc82..038d0b1097 100644 --- a/pkg/agent/agent.go +++ b/pkg/agent/agent.go @@ -14,12 +14,13 @@ import ( "time" "github.com/daytonaio/daytona/cmd/daytona/config" + "github.com/daytonaio/daytona/internal/util" apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" "github.com/daytonaio/daytona/internal/util/apiclient/conversion" agent_config "github.com/daytonaio/daytona/pkg/agent/config" "github.com/daytonaio/daytona/pkg/apiclient" "github.com/daytonaio/daytona/pkg/gitprovider" - "github.com/daytonaio/daytona/pkg/workspace/project" + "github.com/daytonaio/daytona/pkg/models" "github.com/go-git/go-git/v5/plumbing/transport/http" log "github.com/sirupsen/logrus" ) @@ -33,8 +34,13 @@ func (a *Agent) Start() error { a.startTime = time.Now() - if a.Config.Mode == agent_config.ModeProject { - err := a.startProjectMode() + err := a.ensureDefaultProfile() + if err != nil { + return err + } + + if a.Config.Mode == agent_config.ModeWorkspace { + err := a.startWorkspaceMode() if err != nil { return err } @@ -47,6 +53,13 @@ func (a *Agent) Start() error { }() } + if a.Config.Mode == agent_config.ModeTarget { + err := a.startTargetMode() + if err != nil { + return err + } + } + go func() { err := a.Ssh.Start() if err != nil { @@ -65,20 +78,25 @@ func (a *Agent) Start() error { return <-errChan } -func (a *Agent) startProjectMode() error { - err := a.ensureDefaultProfile() - if err != nil { - return err - } +func (a *Agent) startTargetMode() error { + go func() { + for { + err := a.updateTargetMetadata() + if err != nil { + log.Error(fmt.Sprintf("failed to update target state: %s", err)) + } - if a.Config.SkipClone == "" { - project, err := a.getProject() - if err != nil { - return err + time.Sleep(2 * time.Second) } + }() + return nil +} + +func (a *Agent) startWorkspaceMode() error { + if a.Config.SkipClone == "" { // Ignoring error because we don't want to fail if the git provider is not found - gitProvider, _ := a.getGitProvider(project.Repository.Url) + gitProvider, _ := a.getGitProvider(a.Workspace.Repository.Url) var auth *http.BasicAuth if gitProvider != nil { @@ -94,10 +112,10 @@ func (a *Agent) startProjectMode() error { if exists { log.Info("Repository already exists. Skipping clone...") } else { - if stat, err := os.Stat(a.Config.ProjectDir); err == nil { + if stat, err := os.Stat(a.Config.WorkspaceDir); err == nil { ownerUid := stat.Sys().(*syscall.Stat_t).Uid if ownerUid != uint32(os.Getuid()) { - chownCmd := exec.Command("sudo", "chown", "-R", fmt.Sprintf("%s:%s", project.User, project.User), a.Config.ProjectDir) + chownCmd := exec.Command("sudo", "chown", "-R", fmt.Sprintf("%s:%s", a.Workspace.User, a.Workspace.User), a.Config.WorkspaceDir) err = chownCmd.Run() if err != nil { log.Error(err) @@ -106,7 +124,7 @@ func (a *Agent) startProjectMode() error { } log.Info("Cloning repository...") - err = a.Git.CloneRepository(project.Repository, auth) + err = a.Git.CloneRepository(a.Workspace.Repository, auth) if err != nil { log.Error(fmt.Sprintf("failed to clone repository: %s", err)) } else { @@ -130,10 +148,10 @@ func (a *Agent) startProjectMode() error { } } - var providerConfig *gitprovider.GitProviderConfig + var providerConfig *models.GitProviderConfig if gitProvider != nil { - providerConfig = &gitprovider.GitProviderConfig{ - SigningMethod: (*gitprovider.SigningMethod)(gitProvider.SigningMethod), + providerConfig = &models.GitProviderConfig{ + SigningMethod: (*models.SigningMethod)(gitProvider.SigningMethod), SigningKey: gitProvider.SigningKey, } } @@ -143,11 +161,16 @@ func (a *Agent) startProjectMode() error { } } + err := a.DockerCredHelper.SetDockerConfig() + if err != nil { + log.Error(fmt.Sprintf("failed to set docker config: %s", err)) + } + go func() { for { - err := a.updateProjectState() + err := a.updateWorkspaceMetadata() if err != nil { - log.Error(fmt.Sprintf("failed to update project state: %s", err)) + log.Error(fmt.Sprintf("failed to update workspace state: %s", err)) } time.Sleep(2 * time.Second) @@ -157,28 +180,6 @@ func (a *Agent) startProjectMode() error { return nil } -func (a *Agent) getProject() (*project.Project, error) { - ctx := context.Background() - - apiClient, err := apiclient_util.GetAgentApiClient(a.Config.Server.ApiUrl, a.Config.Server.ApiKey, a.Config.ClientId, a.TelemetryEnabled) - if err != nil { - return nil, err - } - - workspace, res, err := apiClient.WorkspaceAPI.GetWorkspace(ctx, a.Config.WorkspaceId).Execute() - if err != nil { - return nil, apiclient_util.HandleErrorResponse(res, err) - } - - for _, project := range workspace.Projects { - if project.Name == a.Config.ProjectName { - return conversion.ToProject(&project), nil - } - } - - return nil, errors.New("project not found") -} - func (a *Agent) getGitProvider(repoUrl string) (*apiclient.GitProvider, error) { ctx := context.Background() @@ -248,13 +249,13 @@ func (a *Agent) uptime() int32 { return max(int32(time.Since(a.startTime).Seconds()), 1) } -func (a *Agent) updateProjectState() error { +func (a *Agent) updateWorkspaceMetadata() error { apiClient, err := apiclient_util.GetAgentApiClient(a.Config.Server.ApiUrl, a.Config.Server.ApiKey, a.Config.ClientId, a.TelemetryEnabled) if err != nil { return err } - var gitStatus *project.GitStatus + var gitStatus *models.GitStatus if a.Config.SkipClone == "" { var err error gitStatus, err = a.Git.GetGitStatus() @@ -264,9 +265,15 @@ func (a *Agent) updateProjectState() error { } uptime := a.uptime() - res, err := apiClient.WorkspaceAPI.SetProjectState(context.Background(), a.Config.WorkspaceId, a.Config.ProjectName).SetState(apiclient.SetProjectState{ + + gitStatusDto, err := conversion.Convert[models.GitStatus, apiclient.GitStatus](gitStatus) + if err != nil { + return err + } + + res, err := apiClient.WorkspaceAPI.UpdateWorkspaceMetadata(context.Background(), a.Config.WorkspaceId).WorkspaceMetadata(apiclient.UpdateWorkspaceMetadataDTO{ Uptime: uptime, - GitStatus: conversion.ToGitStatusDTO(gitStatus), + GitStatus: gitStatusDto, }).Execute() if err != nil { return apiclient_util.HandleErrorResponse(res, err) @@ -274,3 +281,31 @@ func (a *Agent) updateProjectState() error { return nil } + +func (a *Agent) updateTargetMetadata() error { + apiClient, err := apiclient_util.GetAgentApiClient(a.Config.Server.ApiUrl, a.Config.Server.ApiKey, a.Config.ClientId, a.TelemetryEnabled) + if err != nil { + return err + } + + uptime := a.uptime() + res, err := apiClient.TargetAPI.UpdateTargetMetadata(context.Background(), a.Config.TargetId).TargetMetadata(apiclient.UpdateTargetMetadataDTO{ + Uptime: uptime, + }).Execute() + if err != nil { + return apiclient_util.HandleErrorResponse(res, err) + } + + return nil +} + +func (s *Agent) initLogs() { + logFormatter := &util.LogFormatter{ + TextFormatter: &log.TextFormatter{ + ForceColors: true, + }, + ProcessLogWriter: s.LogWriter, + } + + log.SetFormatter(logFormatter) +} diff --git a/pkg/agent/agent_test.go b/pkg/agent/agent_test.go index 9b1cf49fca..7fdf7f6e65 100644 --- a/pkg/agent/agent_test.go +++ b/pkg/agent/agent_test.go @@ -16,59 +16,65 @@ import ( "github.com/daytonaio/daytona/pkg/agent" "github.com/daytonaio/daytona/pkg/agent/config" "github.com/daytonaio/daytona/pkg/gitprovider" - "github.com/daytonaio/daytona/pkg/workspace" - "github.com/daytonaio/daytona/pkg/workspace/project" + "github.com/daytonaio/daytona/pkg/models" ) -var project1 = &project.Project{ +var workspace1 = &models.Workspace{ + Id: "123", Name: "test", Repository: &gitprovider.GitRepository{ Id: "123", Url: "https://github.com/daytonaio/daytona", Name: "daytona", }, - WorkspaceId: "123", - Target: "local", - State: &project.ProjectState{ - UpdatedAt: "123", + TargetId: "123", + Metadata: &models.WorkspaceMetadata{ Uptime: 148, GitStatus: gitStatus1, }, } -var workspace1 = &workspace.Workspace{ - Id: "123", - Name: "test", - Target: "local", - Projects: []*project.Project{ - project1, +var targetConfig1 = &models.TargetConfig{ + Name: "test", + ProviderInfo: models.ProviderInfo{ + Name: "test-provider", + Version: "test", }, + Options: "test-options", + Deleted: false, +} + +var target1 = &models.Target{ + Id: "123", + Name: "test", + TargetConfigId: targetConfig1.Id, + TargetConfig: *targetConfig1, } -var gitStatus1 = &project.GitStatus{ +var gitStatus1 = &models.GitStatus{ CurrentBranch: "main", - Files: []*project.FileStatus{{ + Files: []*models.FileStatus{{ Name: "File1", Extra: "", - Staging: project.Modified, - Worktree: project.Modified, + Staging: models.Modified, + Worktree: models.Modified, }}, } var mockConfig = &config.Config{ + TargetId: target1.Id, WorkspaceId: workspace1.Id, - ProjectName: project1.Name, Server: config.DaytonaServerConfig{ ApiKey: "test-api-key", }, - Mode: config.ModeProject, + Mode: config.ModeWorkspace, } func TestAgent(t *testing.T) { buf := bytes.Buffer{} log.SetOutput(&buf) - apiServer := mocks.NewMockRestServer(t, workspace1) + apiServer := mocks.NewMockRestServer(t) defer apiServer.Close() mockConfig.Server.ApiUrl = apiServer.URL @@ -81,16 +87,19 @@ func TestAgent(t *testing.T) { mockSshServer := mocks.NewMockSshServer() mockTailscaleServer := mocks.NewMockTailscaleServer() mockToolboxServer := mocks.NewMockToolboxServer() + mockDockerCredHelper := mocks.NewMockDockerCredHelper() - mockConfig.ProjectDir = t.TempDir() + mockConfig.WorkspaceDir = t.TempDir() // Create a new Agent instance a := &agent.Agent{ - Config: mockConfig, - Git: mockGitService, - Ssh: mockSshServer, - Tailscale: mockTailscaleServer, - Toolbox: mockToolboxServer, + Config: mockConfig, + Git: mockGitService, + Ssh: mockSshServer, + Tailscale: mockTailscaleServer, + Toolbox: mockToolboxServer, + Workspace: workspace1, + DockerCredHelper: mockDockerCredHelper, } t.Run("Start agent", func(t *testing.T) { @@ -104,16 +113,17 @@ func TestAgent(t *testing.T) { mockSshServer.AssertExpectations(t) mockTailscaleServer.AssertExpectations(t) mockToolboxServer.AssertExpectations(t) + mockDockerCredHelper.AssertExpectations(t) }) } -func TestAgentHostMode(t *testing.T) { +func TestAgentTargetMode(t *testing.T) { mockGitService := mock_git.NewMockGitService() mockSshServer := mocks.NewMockSshServer() mockTailscaleServer := mocks.NewMockTailscaleServer() mockConfig := *mockConfig - mockConfig.Mode = config.ModeHost + mockConfig.Mode = config.ModeTarget // Create a new Agent instance a := &agent.Agent{ @@ -123,8 +133,8 @@ func TestAgentHostMode(t *testing.T) { Tailscale: mockTailscaleServer, } - t.Run("Start agent in host mode", func(t *testing.T) { - mockConfig.Mode = config.ModeHost + t.Run("Start agent in target mode", func(t *testing.T) { + mockConfig.Mode = config.ModeTarget err := a.Start() require.Equal(t, err, mocks.SshServerStartError) diff --git a/pkg/agent/config/config.go b/pkg/agent/config/config.go index 4be2825835..459ce9f574 100644 --- a/pkg/agent/config/config.go +++ b/pkg/agent/config/config.go @@ -21,13 +21,13 @@ type DaytonaServerConfig struct { } type Config struct { - ProjectDir string - ClientId string `envconfig:"DAYTONA_CLIENT_ID" validate:"required"` - ProjectName string `envconfig:"DAYTONA_WS_PROJECT_NAME"` - WorkspaceId string `envconfig:"DAYTONA_WS_ID" validate:"required"` - LogFilePath *string `envconfig:"DAYTONA_AGENT_LOG_FILE_PATH"` - Server DaytonaServerConfig - Mode Mode + WorkspaceDir string + ClientId string `envconfig:"DAYTONA_CLIENT_ID" validate:"required"` + WorkspaceId string `envconfig:"DAYTONA_WORKSPACE_ID"` + TargetId string `envconfig:"DAYTONA_TARGET_ID" validate:"required"` + LogFilePath *string `envconfig:"DAYTONA_AGENT_LOG_FILE_PATH"` + Server DaytonaServerConfig + Mode Mode SkipClone string `envconfig:"DAYTONA_SKIP_CLONE"` } @@ -35,8 +35,8 @@ type Config struct { type Mode string const ( - ModeHost Mode = "host" - ModeProject Mode = "project" + ModeTarget Mode = "target" + ModeWorkspace Mode = "workspace" ) var config *Config @@ -65,9 +65,9 @@ func GetConfig(mode Mode) (*Config, error) { return nil, err } - if config.Mode == ModeProject { - if config.ProjectName == "" { - return nil, errors.New("DAYTONA_WS_PROJECT_NAME is required in project mode") + if config.Mode == ModeWorkspace { + if config.WorkspaceId == "" { + return nil, errors.New("DAYTONA_WORKSPACE_ID is required in workspace mode") } } diff --git a/pkg/agent/log.go b/pkg/agent/log.go deleted file mode 100644 index 61337ab7c6..0000000000 --- a/pkg/agent/log.go +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package agent - -import ( - "io" - - log "github.com/sirupsen/logrus" -) - -type logFormatter struct { - textFormatter *log.TextFormatter - agentLogWriter io.Writer -} - -func (f *logFormatter) Format(entry *log.Entry) ([]byte, error) { - formatted, err := f.textFormatter.Format(entry) - if err != nil { - return nil, err - } - - if f.agentLogWriter != nil { - _, err = f.agentLogWriter.Write(formatted) - if err != nil { - return nil, err - } - } - - // Return the original message without log decoration - // We don't want decoration to show up in the workspace creation logs - return []byte(entry.Message + "\n"), nil -} - -func (s *Agent) initLogs() { - logFormatter := &logFormatter{ - textFormatter: &log.TextFormatter{ - ForceColors: true, - }, - agentLogWriter: s.LogWriter, - } - - log.SetFormatter(logFormatter) -} diff --git a/pkg/agent/ssh/server.go b/pkg/agent/ssh/server.go index d4d8d4d438..9d464ae4d1 100644 --- a/pkg/agent/ssh/server.go +++ b/pkg/agent/ssh/server.go @@ -22,8 +22,8 @@ import ( ) type Server struct { - ProjectDir string - DefaultProjectDir string + WorkspaceDir string + DefaultWorkspaceDir string } func (s *Server) Start() error { @@ -84,10 +84,10 @@ func (s *Server) handlePty(session ssh.Session, ptyReq ssh.Pty, winCh <-chan ssh shell := common.GetShell() cmd := exec.Command(shell) - cmd.Dir = s.ProjectDir + cmd.Dir = s.WorkspaceDir - if _, err := os.Stat(s.ProjectDir); os.IsNotExist(err) { - cmd.Dir = s.DefaultProjectDir + if _, err := os.Stat(s.WorkspaceDir); os.IsNotExist(err) { + cmd.Dir = s.DefaultWorkspaceDir } if ssh.AgentRequested(session) { @@ -143,9 +143,9 @@ func (s *Server) handleNonPty(session ssh.Session) { cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", "SSH_AUTH_SOCK", l.Addr().String())) } - cmd.Dir = s.ProjectDir - if _, err := os.Stat(s.ProjectDir); os.IsNotExist(err) { - cmd.Dir = s.DefaultProjectDir + cmd.Dir = s.WorkspaceDir + if _, err := os.Stat(s.WorkspaceDir); os.IsNotExist(err) { + cmd.Dir = s.DefaultWorkspaceDir } cmd.Stdout = session diff --git a/pkg/agent/tailscale/server.go b/pkg/agent/tailscale/server.go index 7081010e81..0ab2fc9271 100644 --- a/pkg/agent/tailscale/server.go +++ b/pkg/agent/tailscale/server.go @@ -87,7 +87,7 @@ func (s *Server) getNetworkKey() (string, error) { return "", err } - networkKey, _, err := apiClient.ServerAPI.GenerateNetworkKeyExecute(apiclient.ApiGenerateNetworkKeyRequest{}) + networkKey, _, err := apiClient.ServerAPI.CreateNetworkKeyExecute(apiclient.ApiCreateNetworkKeyRequest{}) // Retry indefinitely. Used to reconnect to the Daytona Server if err != nil { log.Tracef("Failed to get network key: %v", err) diff --git a/pkg/agent/toolbox/git/add.go b/pkg/agent/toolbox/git/add.go index 3ab6eb8134..b70053049d 100644 --- a/pkg/agent/toolbox/git/add.go +++ b/pkg/agent/toolbox/git/add.go @@ -16,7 +16,7 @@ func AddFiles(c *gin.Context) { } gitService := git.Service{ - ProjectDir: req.Path, + WorkspaceDir: req.Path, } if err := gitService.Add(req.Files); err != nil { diff --git a/pkg/agent/toolbox/git/clone_repository.go b/pkg/agent/toolbox/git/clone_repository.go index fd5bec42e8..f357d52692 100644 --- a/pkg/agent/toolbox/git/clone_repository.go +++ b/pkg/agent/toolbox/git/clone_repository.go @@ -33,7 +33,7 @@ func CloneRepository(c *gin.Context) { } gitService := git.Service{ - ProjectDir: req.Path, + WorkspaceDir: req.Path, } var auth *http.BasicAuth diff --git a/pkg/agent/toolbox/git/commit.go b/pkg/agent/toolbox/git/commit.go index d03bbbe236..0fd13fd739 100644 --- a/pkg/agent/toolbox/git/commit.go +++ b/pkg/agent/toolbox/git/commit.go @@ -20,7 +20,7 @@ func CommitChanges(c *gin.Context) { } gitService := git.Service{ - ProjectDir: req.Path, + WorkspaceDir: req.Path, } commitSha, err := gitService.Commit(req.Message, &go_git.CommitOptions{ diff --git a/pkg/agent/toolbox/git/create_branch.go b/pkg/agent/toolbox/git/create_branch.go index 5c9d05d97d..ce4d93181e 100644 --- a/pkg/agent/toolbox/git/create_branch.go +++ b/pkg/agent/toolbox/git/create_branch.go @@ -16,7 +16,7 @@ func CreateBranch(c *gin.Context) { } gitService := git.Service{ - ProjectDir: req.Path, + WorkspaceDir: req.Path, } if err := gitService.CreateBranch(req.Name); err != nil { diff --git a/pkg/agent/toolbox/git/history.go b/pkg/agent/toolbox/git/history.go index 1894efe83b..32d4614787 100644 --- a/pkg/agent/toolbox/git/history.go +++ b/pkg/agent/toolbox/git/history.go @@ -18,7 +18,7 @@ func GetCommitHistory(c *gin.Context) { } gitService := git.Service{ - ProjectDir: path, + WorkspaceDir: path, } log, err := gitService.Log() diff --git a/pkg/agent/toolbox/git/list_branches.go b/pkg/agent/toolbox/git/list_branches.go index 18553ebab6..78a48fcdf7 100644 --- a/pkg/agent/toolbox/git/list_branches.go +++ b/pkg/agent/toolbox/git/list_branches.go @@ -18,7 +18,7 @@ func ListBranches(c *gin.Context) { } gitService := git.Service{ - ProjectDir: path, + WorkspaceDir: path, } branchList, err := gitService.ListBranches() diff --git a/pkg/agent/toolbox/git/pull.go b/pkg/agent/toolbox/git/pull.go index ba7727f361..5493acaf7d 100644 --- a/pkg/agent/toolbox/git/pull.go +++ b/pkg/agent/toolbox/git/pull.go @@ -26,7 +26,7 @@ func PullChanges(c *gin.Context) { } gitService := git.Service{ - ProjectDir: req.Path, + WorkspaceDir: req.Path, } err := gitService.Pull(auth) diff --git a/pkg/agent/toolbox/git/push.go b/pkg/agent/toolbox/git/push.go index 94c2459c5f..4217103da5 100644 --- a/pkg/agent/toolbox/git/push.go +++ b/pkg/agent/toolbox/git/push.go @@ -26,7 +26,7 @@ func PushChanges(c *gin.Context) { } gitService := git.Service{ - ProjectDir: req.Path, + WorkspaceDir: req.Path, } err := gitService.Push(auth) diff --git a/pkg/agent/toolbox/git/status.go b/pkg/agent/toolbox/git/status.go index 5e78ffa8ed..2b48cf955a 100644 --- a/pkg/agent/toolbox/git/status.go +++ b/pkg/agent/toolbox/git/status.go @@ -18,7 +18,7 @@ func GetStatus(c *gin.Context) { } gitService := git.Service{ - ProjectDir: path, + WorkspaceDir: path, } status, err := gitService.GetGitStatus() diff --git a/pkg/agent/toolbox/process/execute.go b/pkg/agent/toolbox/process/execute.go index cef4ef3fc5..b34bf1ebca 100644 --- a/pkg/agent/toolbox/process/execute.go +++ b/pkg/agent/toolbox/process/execute.go @@ -14,7 +14,7 @@ import ( "github.com/gin-gonic/gin" ) -func ExecuteCommand(projectDir string) func(c *gin.Context) { +func ExecuteCommand(workspaceDir string) func(c *gin.Context) { return func(c *gin.Context) { var request ExecuteRequest if err := c.ShouldBindJSON(&request); err != nil { @@ -29,7 +29,7 @@ func ExecuteCommand(projectDir string) func(c *gin.Context) { } cmd := exec.Command(cmdParts[0], cmdParts[1:]...) - cmd.Dir = projectDir + cmd.Dir = workspaceDir // set maximum execution time timeout := 10 * time.Second diff --git a/pkg/agent/toolbox/process/session/execute.go b/pkg/agent/toolbox/process/session/execute.go index 35f2eb67f4..b7feff1d7e 100644 --- a/pkg/agent/toolbox/process/session/execute.go +++ b/pkg/agent/toolbox/process/session/execute.go @@ -16,6 +16,7 @@ import ( "strings" "github.com/daytonaio/daytona/internal/util" + "github.com/daytonaio/daytona/pkg/logs" "github.com/gin-gonic/gin" "github.com/google/uuid" ) @@ -77,7 +78,7 @@ func SessionExecuteCommand(configDir string) func(c *gin.Context) { logChan := make(chan []byte) errChan := make(chan error) - go util.ReadLog(context.Background(), logFile, true, logChan, errChan) + go logs.ReadLog(context.Background(), logFile, true, logChan, errChan) defer logFile.Close() diff --git a/pkg/agent/toolbox/process/session/log.go b/pkg/agent/toolbox/process/session/log.go index 8ed28c5805..76e05d1f91 100644 --- a/pkg/agent/toolbox/process/session/log.go +++ b/pkg/agent/toolbox/process/session/log.go @@ -8,8 +8,8 @@ import ( "net/http" "os" - "github.com/daytonaio/daytona/internal/util" "github.com/daytonaio/daytona/pkg/api/controllers/log" + "github.com/daytonaio/daytona/pkg/logs" "github.com/gin-gonic/gin" "github.com/gorilla/websocket" ) @@ -44,7 +44,7 @@ func GetSessionCommandLogs(configDir string) func(c *gin.Context) { return } defer logFile.Close() - log.ReadLog(c, logFile, util.ReadLog, func(conn *websocket.Conn, messages chan []byte, errors chan error) { + log.ReadLog(c, logFile, logs.ReadLog, func(conn *websocket.Conn, messages chan []byte, errors chan error) { for { msg := <-messages _, output := extractExitCode(string(msg)) diff --git a/pkg/agent/toolbox/process/session/session.go b/pkg/agent/toolbox/process/session/session.go index 968d348fce..585cec1efc 100644 --- a/pkg/agent/toolbox/process/session/session.go +++ b/pkg/agent/toolbox/process/session/session.go @@ -18,11 +18,11 @@ import ( var sessions = map[string]*session{} -func CreateSession(projectDir, configDir string) func(c *gin.Context) { +func CreateSession(workspaceDir, configDir string) func(c *gin.Context) { return func(c *gin.Context) { cmd := exec.Command(common.GetShell()) cmd.Env = os.Environ() - cmd.Dir = projectDir + cmd.Dir = workspaceDir var request CreateSessionRequest if err := c.ShouldBindJSON(&request); err != nil { diff --git a/pkg/agent/toolbox/toolbox.go b/pkg/agent/toolbox/toolbox.go index d02211edac..cfb720b791 100644 --- a/pkg/agent/toolbox/toolbox.go +++ b/pkg/agent/toolbox/toolbox.go @@ -21,20 +21,20 @@ import ( ) type Server struct { - ProjectDir string - ConfigDir string + ConfigDir string + WorkspaceDir string } -type ProjectDirResponse struct { +type WorkspaceDirResponse struct { Dir string `json:"dir"` -} // @name ProjectDirResponse +} // @name WorkspaceDirResponse -func (s *Server) GetProjectDir(ctx *gin.Context) { - projectDir := ProjectDirResponse{ - Dir: s.ProjectDir, +func (s *Server) GetWorkspaceDir(ctx *gin.Context) { + workspaceDir := WorkspaceDirResponse{ + Dir: s.WorkspaceDir, } - ctx.JSON(200, projectDir) + ctx.JSON(200, workspaceDir) } func (s *Server) Start() error { @@ -43,7 +43,7 @@ func (s *Server) Start() error { r.Use(middlewares.LoggingMiddleware()) binding.Validator = new(api.DefaultValidator) - r.GET("/project-dir", s.GetProjectDir) + r.GET("/workspace-dir", s.GetWorkspaceDir) fsController := r.Group("/files") { @@ -67,12 +67,12 @@ func (s *Server) Start() error { processController := r.Group("/process") { - processController.POST("/execute", process.ExecuteCommand(s.ProjectDir)) + processController.POST("/execute", process.ExecuteCommand(s.WorkspaceDir)) sessionController := processController.Group("/session") { sessionController.GET("", session.ListSessions) - sessionController.POST("", session.CreateSession(s.ProjectDir, s.ConfigDir)) + sessionController.POST("", session.CreateSession(s.WorkspaceDir, s.ConfigDir)) sessionController.POST("/:sessionId/exec", session.SessionExecuteCommand(s.ConfigDir)) sessionController.DELETE("/:sessionId", session.DeleteSession(s.ConfigDir)) sessionController.GET("/:sessionId/command/:commandId/logs", session.GetSessionCommandLogs(s.ConfigDir)) diff --git a/pkg/agent/types.go b/pkg/agent/types.go index f01687761a..eb0a613322 100644 --- a/pkg/agent/types.go +++ b/pkg/agent/types.go @@ -8,7 +8,9 @@ import ( "time" "github.com/daytonaio/daytona/pkg/agent/config" + "github.com/daytonaio/daytona/pkg/docker" "github.com/daytonaio/daytona/pkg/git" + "github.com/daytonaio/daytona/pkg/models" ) type SshServer interface { @@ -26,10 +28,12 @@ type ToolboxServer interface { type Agent struct { Config *config.Config Git git.IGitService + DockerCredHelper docker.IDockerCredHelper Ssh SshServer Toolbox ToolboxServer Tailscale TailscaleServer LogWriter io.Writer TelemetryEnabled bool startTime time.Time + Workspace *models.Workspace } diff --git a/pkg/api/controllers/apikey/apikey.go b/pkg/api/controllers/apikey/apikey.go index 811501908c..5bd9aaabee 100644 --- a/pkg/api/controllers/apikey/apikey.go +++ b/pkg/api/controllers/apikey/apikey.go @@ -7,7 +7,11 @@ import ( "fmt" "net/http" + internal_util "github.com/daytonaio/daytona/internal/util" + "github.com/daytonaio/daytona/pkg/api/controllers/apikey/dto" + "github.com/daytonaio/daytona/pkg/api/util" "github.com/daytonaio/daytona/pkg/server" + "github.com/daytonaio/daytona/pkg/services" "github.com/gin-gonic/gin" ) @@ -17,40 +21,57 @@ import ( // @Summary List API keys // @Description List API keys // @Produce json -// @Success 200 {array} ApiKey +// @Success 200 {array} ApiKeyViewDTO // @Router /apikey [get] // // @id ListClientApiKeys func ListClientApiKeys(ctx *gin.Context) { server := server.GetInstance(nil) - response, err := server.ApiKeyService.ListClientKeys() + currentApiKeyName, _ := server.ApiKeyService.GetApiKeyName(ctx.Request.Context(), util.ExtractToken(ctx)) + + response, err := server.ApiKeyService.ListClientKeys(ctx.Request.Context()) if err != nil { ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to get client API keys: %w", err)) return } - ctx.JSON(200, response) + result := internal_util.ArrayMap(response, func(key *services.ApiKeyDTO) dto.ApiKeyViewDTO { + return dto.ApiKeyViewDTO{Name: key.Name, Type: key.Type, Current: key.Name == currentApiKeyName} + }) + + ctx.JSON(200, result) } -// RevokeApiKey godoc +// DeleteApiKey godoc // // @Tags apiKey -// @Summary Revoke API key -// @Description Revoke API key +// @Summary Delete API key +// @Description Delete API key // @Param apiKeyName path string true "API key name" // @Success 200 // @Router /apikey/{apiKeyName} [delete] // -// @id RevokeApiKey -func RevokeApiKey(ctx *gin.Context) { +// @id DeleteApiKey +func DeleteApiKey(ctx *gin.Context) { apiKeyName := ctx.Param("apiKeyName") server := server.GetInstance(nil) - err := server.ApiKeyService.Revoke(apiKeyName) + currentApiKeyName, err := server.ApiKeyService.GetApiKeyName(ctx.Request.Context(), util.ExtractToken(ctx)) + if err != nil { + ctx.AbortWithError(http.StatusNotFound, fmt.Errorf("failed to get current api key name: %w", err)) + return + } + + if currentApiKeyName == apiKeyName { + ctx.AbortWithError(http.StatusForbidden, fmt.Errorf("cannot delete current api key")) + return + } + + err = server.ApiKeyService.Delete(ctx.Request.Context(), apiKeyName) if err != nil { - ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to revoke api key: %w", err)) + ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to delete api key: %w", err)) return } diff --git a/pkg/api/controllers/apikey/generate.go b/pkg/api/controllers/apikey/create.go similarity index 67% rename from pkg/api/controllers/apikey/generate.go rename to pkg/api/controllers/apikey/create.go index 2d4fe8fa56..e656343ae5 100644 --- a/pkg/api/controllers/apikey/generate.go +++ b/pkg/api/controllers/apikey/create.go @@ -7,28 +7,28 @@ import ( "fmt" "net/http" - "github.com/daytonaio/daytona/pkg/apikey" + "github.com/daytonaio/daytona/pkg/models" "github.com/daytonaio/daytona/pkg/server" "github.com/gin-gonic/gin" ) -// GenerateApiKey godoc +// CreateApiKey godoc // // @Tags apiKey -// @Summary Generate an API key -// @Description Generate an API key +// @Summary Create an API key +// @Description Create an API key // @Produce plain // @Param apiKeyName path string true "API key name" // @Success 200 {string} apiKey // @Router /apikey/{apiKeyName} [post] // -// @id GenerateApiKey -func GenerateApiKey(ctx *gin.Context) { +// @id CreateApiKey +func CreateApiKey(ctx *gin.Context) { apiKeyName := ctx.Param("apiKeyName") server := server.GetInstance(nil) - response, err := server.ApiKeyService.Generate(apikey.ApiKeyTypeClient, apiKeyName) + response, err := server.ApiKeyService.Create(ctx.Request.Context(), models.ApiKeyTypeClient, apiKeyName) if err != nil { ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to get API keys: %w", err)) return diff --git a/pkg/api/controllers/apikey/dto/apikey.go b/pkg/api/controllers/apikey/dto/apikey.go new file mode 100644 index 0000000000..27aeb6ffbe --- /dev/null +++ b/pkg/api/controllers/apikey/dto/apikey.go @@ -0,0 +1,12 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package dto + +import "github.com/daytonaio/daytona/pkg/models" + +type ApiKeyViewDTO struct { + Type models.ApiKeyType `json:"type" validate:"required"` + Name string `json:"name" validate:"required"` + Current bool `json:"current" validate:"required"` +} // @name ApiKeyViewDTO diff --git a/pkg/api/controllers/binary/get_daytona.go b/pkg/api/controllers/binary/get_daytona.go index 3d7aff1fe9..1759862742 100644 --- a/pkg/api/controllers/binary/get_daytona.go +++ b/pkg/api/controllers/binary/get_daytona.go @@ -12,7 +12,7 @@ import ( "github.com/gin-gonic/gin" ) -// Used in projects to download the Daytona binary +// Used in workspaces to download the Daytona binary func GetDaytonaScript(ctx *gin.Context) { scheme := "http" if ctx.Request.TLS != nil || ctx.GetHeader("X-Forwarded-Proto") == "https" { diff --git a/pkg/api/controllers/build/build.go b/pkg/api/controllers/build/build.go deleted file mode 100644 index 36ea2f8d51..0000000000 --- a/pkg/api/controllers/build/build.go +++ /dev/null @@ -1,265 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package build - -import ( - "errors" - "fmt" - "net/http" - "strconv" - - "github.com/daytonaio/daytona/pkg/api/controllers/build/dto" - "github.com/daytonaio/daytona/pkg/build" - "github.com/daytonaio/daytona/pkg/gitprovider" - "github.com/daytonaio/daytona/pkg/server" - builds_dto "github.com/daytonaio/daytona/pkg/server/builds/dto" - "github.com/daytonaio/daytona/pkg/workspace/project/config" - "github.com/gin-gonic/gin" -) - -// CreateBuild godoc -// -// @Tags build -// @Summary Create a build -// @Description Create a build -// @Accept json -// @Param createBuildDto body CreateBuildDTO true "Create Build DTO" -// @Success 201 {string} buildId -// @Router /build [post] -// -// @id CreateBuild -func CreateBuild(ctx *gin.Context) { - var createBuildDto dto.CreateBuildDTO - err := ctx.BindJSON(&createBuildDto) - if err != nil { - ctx.AbortWithError(http.StatusBadRequest, fmt.Errorf("invalid request body: %s", err.Error())) - return - } - - s := server.GetInstance(nil) - - projectConfig, err := s.ProjectConfigService.Find(&config.ProjectConfigFilter{ - Name: &createBuildDto.ProjectConfigName, - }) - if err != nil { - ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to get project config: %s", err.Error())) - return - } - - gitProvider, _, err := s.GitProviderService.GetGitProviderForUrl(projectConfig.RepositoryUrl) - if err != nil { - ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to get git provider for url: %s", err.Error())) - return - } - - repo, err := gitProvider.GetRepositoryContext(gitprovider.GetRepositoryContext{ - Url: projectConfig.RepositoryUrl, - Branch: &createBuildDto.Branch, - }) - if err != nil { - ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to get repository: %s", err.Error())) - return - } - - newBuildDto := builds_dto.BuildCreationData{ - Image: projectConfig.Image, - User: projectConfig.User, - BuildConfig: projectConfig.BuildConfig, - Repository: repo, - EnvVars: createBuildDto.EnvVars, - } - - if createBuildDto.PrebuildId != nil { - newBuildDto.PrebuildId = *createBuildDto.PrebuildId - } - - buildId, err := s.BuildService.Create(newBuildDto) - if err != nil { - ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to create build: %s", err.Error())) - return - } - - ctx.String(201, buildId) -} - -// GetBuild godoc -// -// @Tags build -// @Summary Get build data -// @Description Get build data -// @Accept json -// @Param buildId path string true "Build ID" -// @Success 200 {object} Build -// @Router /build/{buildId} [get] -// -// @id GetBuild -func GetBuild(ctx *gin.Context) { - buildId := ctx.Param("buildId") - - server := server.GetInstance(nil) - - b, err := server.BuildService.Find(&build.Filter{ - Id: &buildId, - }) - if err != nil { - statusCode := http.StatusInternalServerError - if build.IsBuildNotFound(err) { - statusCode = http.StatusNotFound - } - ctx.AbortWithError(statusCode, fmt.Errorf("failed to find build: %w", err)) - return - } - - ctx.JSON(200, b) -} - -// ListBuilds godoc -// -// @Tags build -// @Summary List builds -// @Description List builds -// @Produce json -// @Success 200 {array} Build -// @Router /build [get] -// -// @id ListBuilds -func ListBuilds(ctx *gin.Context) { - server := server.GetInstance(nil) - - builds, err := server.BuildService.List(nil) - if err != nil { - ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to list builds: %s", err.Error())) - return - } - - ctx.JSON(200, builds) -} - -// DeleteAllBuilds godoc -// -// @Tags build -// @Summary Delete ALL builds -// @Description Delete ALL builds -// @Param force query bool false "Force" -// @Success 204 -// @Router /build [delete] -// -// @id DeleteAllBuilds -func DeleteAllBuilds(ctx *gin.Context) { - forceQuery := ctx.Query("force") - var force bool - var err error - - if forceQuery != "" { - force, err = strconv.ParseBool(forceQuery) - if err != nil { - ctx.AbortWithError(http.StatusBadRequest, errors.New("invalid value for force flag")) - return - } - } - - server := server.GetInstance(nil) - - errs := server.BuildService.MarkForDeletion(nil, force) - if len(errs) > 0 { - for _, err := range errs { - _ = ctx.Error(err) - } - ctx.AbortWithStatus(http.StatusInternalServerError) - return - } - - ctx.Status(204) -} - -// DeleteBuild godoc -// -// @Tags build -// @Summary Delete build -// @Description Delete build -// @Param buildId path string true "Build ID" -// @Param force query bool false "Force" -// @Success 204 -// @Router /build/{buildId} [delete] -// -// @id DeleteBuild -func DeleteBuild(ctx *gin.Context) { - buildId := ctx.Param("buildId") - forceQuery := ctx.Query("force") - var force bool - var err error - - if forceQuery != "" { - force, err = strconv.ParseBool(forceQuery) - if err != nil { - ctx.AbortWithError(http.StatusBadRequest, errors.New("invalid value for force flag")) - return - } - } - - server := server.GetInstance(nil) - - errs := server.BuildService.MarkForDeletion(&build.Filter{ - Id: &buildId, - }, force) - if len(errs) > 0 { - for _, err := range errs { - _ = ctx.Error(err) - } - ctx.AbortWithStatus(http.StatusInternalServerError) - return - } - - ctx.Status(204) -} - -// DeleteBuildsFromPrebuild godoc -// -// @Tags build -// @Summary Delete builds -// @Description Delete builds -// @Param prebuildId path string true "Prebuild ID" -// @Param force query bool false "Force" -// @Success 204 -// @Router /build/prebuild/{prebuildId} [delete] -// -// @id DeleteBuildsFromPrebuild -func DeleteBuildsFromPrebuild(ctx *gin.Context) { - prebuildId := ctx.Param("prebuildId") - forceQuery := ctx.Query("force") - var force bool - var err error - - if forceQuery != "" { - force, err = strconv.ParseBool(forceQuery) - if err != nil { - ctx.AbortWithError(http.StatusBadRequest, errors.New("invalid value for force flag")) - return - } - } - - server := server.GetInstance(nil) - - // Fail if prebuild does not exist - _, err = server.ProjectConfigService.FindPrebuild(nil, &config.PrebuildFilter{ - Id: &prebuildId, - }) - if err != nil { - ctx.AbortWithError(http.StatusBadRequest, fmt.Errorf("failed to find prebuild: %s", err.Error())) - return - } - - errs := server.BuildService.MarkForDeletion(&build.Filter{ - PrebuildIds: &[]string{prebuildId}, - }, force) - if len(errs) > 0 { - for _, err := range errs { - _ = ctx.Error(err) - } - ctx.AbortWithStatus(http.StatusInternalServerError) - return - } - - ctx.Status(204) -} diff --git a/pkg/api/controllers/build/create.go b/pkg/api/controllers/build/create.go new file mode 100644 index 0000000000..93f2c7180a --- /dev/null +++ b/pkg/api/controllers/build/create.go @@ -0,0 +1,43 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package build + +import ( + "fmt" + "net/http" + + "github.com/daytonaio/daytona/pkg/server" + "github.com/daytonaio/daytona/pkg/services" + "github.com/gin-gonic/gin" +) + +// CreateBuild godoc +// +// @Tags build +// @Summary Create a build +// @Description Create a build +// @Accept json +// @Param createBuildDto body CreateBuildDTO true "Create Build DTO" +// @Success 201 {string} buildId +// @Router /build [post] +// +// @id CreateBuild +func CreateBuild(ctx *gin.Context) { + var createBuildDto services.CreateBuildDTO + err := ctx.BindJSON(&createBuildDto) + if err != nil { + ctx.AbortWithError(http.StatusBadRequest, fmt.Errorf("invalid request body: %s", err.Error())) + return + } + + s := server.GetInstance(nil) + + buildId, err := s.BuildService.Create(ctx.Request.Context(), createBuildDto) + if err != nil { + ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to create build: %s", err.Error())) + return + } + + ctx.String(201, buildId) +} diff --git a/pkg/api/controllers/build/delete.go b/pkg/api/controllers/build/delete.go new file mode 100644 index 0000000000..a3fff19231 --- /dev/null +++ b/pkg/api/controllers/build/delete.go @@ -0,0 +1,148 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package build + +import ( + "errors" + "fmt" + "net/http" + "strconv" + + "github.com/daytonaio/daytona/pkg/server" + "github.com/daytonaio/daytona/pkg/services" + "github.com/daytonaio/daytona/pkg/stores" + "github.com/gin-gonic/gin" +) + +// DeleteAllBuilds godoc +// +// @Tags build +// @Summary Delete ALL builds +// @Description Delete ALL builds +// @Param force query bool false "Force" +// @Success 204 +// @Router /build [delete] +// +// @id DeleteAllBuilds +func DeleteAllBuilds(ctx *gin.Context) { + forceQuery := ctx.Query("force") + var force bool + var err error + + if forceQuery != "" { + force, err = strconv.ParseBool(forceQuery) + if err != nil { + ctx.AbortWithError(http.StatusBadRequest, errors.New("invalid value for force flag")) + return + } + } + + server := server.GetInstance(nil) + + errs := server.BuildService.Delete(ctx.Request.Context(), nil, force) + if len(errs) > 0 { + for _, err := range errs { + _ = ctx.Error(err) + } + ctx.AbortWithStatus(http.StatusInternalServerError) + return + } + + ctx.Status(204) +} + +// DeleteBuild godoc +// +// @Tags build +// @Summary Delete build +// @Description Delete build +// @Param buildId path string true "Build ID" +// @Param force query bool false "Force" +// @Success 204 +// @Router /build/{buildId} [delete] +// +// @id DeleteBuild +func DeleteBuild(ctx *gin.Context) { + buildId := ctx.Param("buildId") + forceQuery := ctx.Query("force") + var force bool + var err error + + if forceQuery != "" { + force, err = strconv.ParseBool(forceQuery) + if err != nil { + ctx.AbortWithError(http.StatusBadRequest, errors.New("invalid value for force flag")) + return + } + } + + server := server.GetInstance(nil) + + errs := server.BuildService.Delete(ctx.Request.Context(), &services.BuildFilter{ + StoreFilter: stores.BuildFilter{ + Id: &buildId, + }, + }, force) + if len(errs) > 0 { + for _, err := range errs { + _ = ctx.Error(err) + } + ctx.AbortWithStatus(http.StatusInternalServerError) + return + } + + ctx.Status(204) +} + +// DeleteBuildsFromPrebuild godoc +// +// @Tags build +// @Summary Delete builds +// @Description Delete builds +// @Param prebuildId path string true "Prebuild ID" +// @Param force query bool false "Force" +// @Success 204 +// @Router /build/prebuild/{prebuildId} [delete] +// +// @id DeleteBuildsFromPrebuild +func DeleteBuildsFromPrebuild(ctx *gin.Context) { + prebuildId := ctx.Param("prebuildId") + forceQuery := ctx.Query("force") + var force bool + var err error + + if forceQuery != "" { + force, err = strconv.ParseBool(forceQuery) + if err != nil { + ctx.AbortWithError(http.StatusBadRequest, errors.New("invalid value for force flag")) + return + } + } + + server := server.GetInstance(nil) + + // Fail if prebuild does not exist + _, err = server.WorkspaceTemplateService.FindPrebuild(ctx.Request.Context(), nil, &stores.PrebuildFilter{ + Id: &prebuildId, + }) + if err != nil { + ctx.AbortWithError(http.StatusBadRequest, fmt.Errorf("failed to find prebuild: %s", err.Error())) + return + } + + errs := server.BuildService.Delete(ctx.Request.Context(), &services.BuildFilter{ + StoreFilter: stores.BuildFilter{ + PrebuildIds: &[]string{prebuildId}, + }, + }, force) + if len(errs) > 0 { + for _, err := range errs { + _ = ctx.Error(err) + } + ctx.AbortWithStatus(http.StatusInternalServerError) + return + } + + ctx.Status(204) +} diff --git a/pkg/api/controllers/build/dto/dto.go b/pkg/api/controllers/build/dto/dto.go deleted file mode 100644 index f97ef23c04..0000000000 --- a/pkg/api/controllers/build/dto/dto.go +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package dto - -type CreateBuildDTO struct { - ProjectConfigName string `json:"projectConfigName" validate:"required"` - Branch string `json:"branch" validate:"required"` - PrebuildId *string `json:"prebuildId" validate:"optional"` - EnvVars map[string]string `json:"envVars" validate:"required"` -} // @name CreateBuildDTO diff --git a/pkg/api/controllers/build/find.go b/pkg/api/controllers/build/find.go new file mode 100644 index 0000000000..bd0c9cd5cb --- /dev/null +++ b/pkg/api/controllers/build/find.go @@ -0,0 +1,47 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package build + +import ( + "fmt" + "net/http" + + "github.com/daytonaio/daytona/pkg/server" + "github.com/daytonaio/daytona/pkg/services" + "github.com/daytonaio/daytona/pkg/stores" + "github.com/gin-gonic/gin" +) + +// FindBuild godoc +// +// @Tags build +// @Summary Find build +// @Description Find build +// @Accept json +// @Param buildId path string true "Build ID" +// @Success 200 {object} BuildDTO +// @Router /build/{buildId} [get] +// +// @id FindBuild +func FindBuild(ctx *gin.Context) { + buildId := ctx.Param("buildId") + + server := server.GetInstance(nil) + + b, err := server.BuildService.Find(ctx.Request.Context(), &services.BuildFilter{ + StoreFilter: stores.BuildFilter{ + Id: &buildId, + }, + }) + if err != nil { + statusCode := http.StatusInternalServerError + if stores.IsBuildNotFound(err) || services.IsBuildDeleted(err) { + statusCode = http.StatusNotFound + } + ctx.AbortWithError(statusCode, fmt.Errorf("failed to find build: %w", err)) + return + } + + ctx.JSON(200, b) +} diff --git a/pkg/api/controllers/build/list.go b/pkg/api/controllers/build/list.go new file mode 100644 index 0000000000..654c362356 --- /dev/null +++ b/pkg/api/controllers/build/list.go @@ -0,0 +1,74 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package build + +import ( + "fmt" + "net/http" + "net/url" + + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/server" + "github.com/daytonaio/daytona/pkg/services" + "github.com/daytonaio/daytona/pkg/stores" + "github.com/gin-gonic/gin" +) + +// ListBuilds godoc +// +// @Tags build +// @Summary List builds +// @Description List builds +// @Produce json +// @Success 200 {array} BuildDTO +// @Router /build [get] +// +// @id ListBuilds +func ListBuilds(ctx *gin.Context) { + server := server.GetInstance(nil) + + builds, err := server.BuildService.List(ctx.Request.Context(), nil) + if err != nil { + ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to list builds: %s", err.Error())) + return + } + + ctx.JSON(200, builds) +} + +// ListSuccessfulBuilds godoc +// +// @Tags build +// @Summary List successful builds for Git repository +// @Description List successful builds for Git repository +// @Produce json +// @Param repoUrl path string true "Repository URL" +// @Success 200 {array} BuildDTO +// @Router /build/successful/{repoUrl} [get] +// +// @id ListSuccessfulBuilds +func ListSuccessfulBuilds(ctx *gin.Context) { + urlParam := ctx.Param("url") + + decodedUrl, err := url.QueryUnescape(urlParam) + if err != nil { + ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to decode query param: %w", err)) + return + } + + server := server.GetInstance(nil) + + builds, err := server.BuildService.List(ctx.Request.Context(), &services.BuildFilter{ + StateNames: &[]models.ResourceStateName{models.ResourceStateNameRunSuccessful}, + StoreFilter: stores.BuildFilter{ + RepositoryUrl: &decodedUrl, + }, + }) + if err != nil { + ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to list successful builds: %s", err.Error())) + return + } + + ctx.JSON(200, builds) +} diff --git a/pkg/api/controllers/containerregistry/find.go b/pkg/api/controllers/containerregistry/find.go new file mode 100644 index 0000000000..2133258bd6 --- /dev/null +++ b/pkg/api/controllers/containerregistry/find.go @@ -0,0 +1,67 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package containerregistry + +import ( + "fmt" + "net/http" + + internal_util "github.com/daytonaio/daytona/internal/util" + "github.com/daytonaio/daytona/pkg/server" + "github.com/daytonaio/daytona/pkg/services" + "github.com/daytonaio/daytona/pkg/stores" + "github.com/gin-gonic/gin" +) + +// FindContainerRegistry godoc +// +// @Tags container registry +// @Summary Find container registry +// @Description Find container registry +// @Produce json +// @Param server path string true "Container registry server" +// @Param workspaceId query string false "Workspace ID or Name" +// @Success 200 {object} ContainerRegistry +// @Router /container-registry/{server} [get] +// +// @id FindContainerRegistry +func FindContainerRegistry(ctx *gin.Context) { + serverName := ctx.Param("server") + workspaceId := ctx.Query("workspaceId") + + var envVars map[string]string + var err error + + server := server.GetInstance(nil) + + serverEnvVars, err := server.EnvironmentVariableService.Map(ctx.Request.Context()) + if err != nil { + ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to fetch environment variables: %w", err)) + return + } + + envVars = serverEnvVars + + if workspaceId != "" { + w, err := server.WorkspaceService.Find(ctx.Request.Context(), workspaceId, services.WorkspaceRetrievalParams{}) + if err != nil { + statusCode := http.StatusInternalServerError + if stores.IsWorkspaceNotFound(err) || services.IsWorkspaceDeleted(err) { + statusCode = http.StatusNotFound + } + ctx.AbortWithError(statusCode, fmt.Errorf("failed to find workspace: %w", err)) + return + } + + envVars = internal_util.MergeEnvVars(serverEnvVars, w.EnvVars) + } + + cr := services.EnvironmentVariables(envVars).FindContainerRegistry(serverName) + if cr == nil { + ctx.AbortWithError(http.StatusNotFound, fmt.Errorf("failed to find container registry for server: %s", serverName)) + return + } + + ctx.JSON(200, cr) +} diff --git a/pkg/api/controllers/containerregistry/list.go b/pkg/api/controllers/containerregistry/list.go deleted file mode 100644 index 29ba7219fd..0000000000 --- a/pkg/api/controllers/containerregistry/list.go +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package containerregistry - -import ( - "fmt" - "net/http" - "net/url" - - "github.com/daytonaio/daytona/pkg/server" - "github.com/gin-gonic/gin" -) - -// GetContainerRegistry godoc -// -// @Tags container-registry -// @Summary Get container registry credentials -// @Description Get container registry credentials -// @Produce json -// @Param server path string true "Container Registry server name" -// @Success 200 {object} ContainerRegistry -// @Router /container-registry/{server} [get] -// -// @id GetContainerRegistry -func GetContainerRegistry(ctx *gin.Context) { - crServer := ctx.Param("server") - - decodedServerURL, err := url.QueryUnescape(crServer) - if err != nil { - ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to decode server URL: %w", err)) - return - } - - server := server.GetInstance(nil) - - cr, err := server.ContainerRegistryService.Find(decodedServerURL) - if err != nil { - ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to get container registry: %w", err)) - return - } - - cr.Password = "" - - ctx.JSON(200, cr) -} - -// ListContainerRegistries godoc -// -// @Tags container-registry -// @Summary List container registries -// @Description List container registries -// @Produce json -// @Success 200 {array} ContainerRegistry -// @Router /container-registry [get] -// -// @id ListContainerRegistries -func ListContainerRegistries(ctx *gin.Context) { - server := server.GetInstance(nil) - - crs, err := server.ContainerRegistryService.List() - if err != nil { - ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to list container registries: %w", err)) - return - } - - for _, cr := range crs { - cr.Password = "" - } - - ctx.JSON(200, crs) -} diff --git a/pkg/api/controllers/containerregistry/remove.go b/pkg/api/controllers/containerregistry/remove.go deleted file mode 100644 index a1a9d2b57a..0000000000 --- a/pkg/api/controllers/containerregistry/remove.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package containerregistry - -import ( - "fmt" - "net/http" - "net/url" - - "github.com/daytonaio/daytona/pkg/server" - "github.com/gin-gonic/gin" -) - -// RemoveContainerRegistry godoc -// -// @Tags container-registry -// @Summary Remove a container registry credentials -// @Description Remove a container registry credentials -// @Param server path string true "Container Registry server name" -// @Success 204 -// @Router /container-registry/{server} [delete] -// -// @id RemoveContainerRegistry -func RemoveContainerRegistry(ctx *gin.Context) { - crServer := ctx.Param("server") - - decodedServerURL, err := url.QueryUnescape(crServer) - if err != nil { - ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to decode server URL: %w", err)) - return - } - - server := server.GetInstance(nil) - - err = server.ContainerRegistryService.Delete(decodedServerURL) - if err != nil { - ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to remove container registry: %w", err)) - return - } - - ctx.Status(204) -} diff --git a/pkg/api/controllers/containerregistry/set.go b/pkg/api/controllers/containerregistry/set.go deleted file mode 100644 index aadb0e63a0..0000000000 --- a/pkg/api/controllers/containerregistry/set.go +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package containerregistry - -import ( - "fmt" - "net/http" - "net/url" - - "github.com/daytonaio/daytona/pkg/containerregistry" - "github.com/daytonaio/daytona/pkg/server" - "github.com/gin-gonic/gin" -) - -// SetContainerRegistry godoc -// -// @Tags container-registry -// @Summary Set container registry credentials -// @Description Set container registry credentials -// @Param server path string true "Container Registry server name" -// @Param containerRegistry body ContainerRegistry true "Container Registry credentials to set" -// @Success 201 -// @Router /container-registry/{server} [put] -// -// @id SetContainerRegistry -func SetContainerRegistry(ctx *gin.Context) { - crServer := ctx.Param("server") - - decodedServerURL, err := url.QueryUnescape(crServer) - if err != nil { - ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to decode server URL: %w", err)) - return - } - - var req containerregistry.ContainerRegistry - err = ctx.BindJSON(&req) - if err != nil { - ctx.AbortWithError(http.StatusBadRequest, fmt.Errorf("invalid request body: %w", err)) - return - } - - server := server.GetInstance(nil) - - cr, err := server.ContainerRegistryService.Find(decodedServerURL) - if err == nil { - err = server.ContainerRegistryService.Delete(decodedServerURL) - if err != nil { - ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to remove container registry: %w", err)) - return - } - - cr.Server = req.Server - cr.Username = req.Username - cr.Password = req.Password - } else { - cr = &req - } - - err = server.ContainerRegistryService.Save(cr) - if err != nil { - ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to set container registry: %w", err)) - return - } - - ctx.Status(201) -} diff --git a/pkg/api/controllers/env/env.go b/pkg/api/controllers/env/env.go new file mode 100644 index 0000000000..ebbabd4f70 --- /dev/null +++ b/pkg/api/controllers/env/env.go @@ -0,0 +1,96 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package env + +import ( + "fmt" + "net/http" + + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/server" + "github.com/daytonaio/daytona/pkg/stores" + "github.com/gin-gonic/gin" +) + +// ListEnvironmentVariables godoc +// +// @Tags envVar +// @Summary List environment variables +// @Description List environment variables +// @Produce json +// @Success 200 {array} models.EnvironmentVariable +// @Router /env [get] +// +// @id ListEnvironmentVariables +func ListEnvironmentVariables(ctx *gin.Context) { + server := server.GetInstance(nil) + envVars, err := server.EnvironmentVariableService.List(ctx.Request.Context()) + if err != nil { + if stores.IsEnvironmentVariableNotFound(err) { + ctx.JSON(200, []*models.EnvironmentVariable{}) + return + } + ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to list environment variables: %w", err)) + return + } + + ctx.JSON(200, envVars) +} + +// SaveEnvironmentVariable godoc +// +// @Tags envVar +// @Summary Save environment variable +// @Description Save environment variable +// @Accept json +// @Param environmentVariable body models.EnvironmentVariable true "Environment Variable" +// @Success 201 +// @Router /env [put] +// +// @id SaveEnvironmentVariable +func SaveEnvironmentVariable(ctx *gin.Context) { + var req models.EnvironmentVariable + err := ctx.BindJSON(&req) + if err != nil { + ctx.AbortWithError(http.StatusBadRequest, fmt.Errorf("invalid request body: %w", err)) + return + } + + server := server.GetInstance(nil) + err = server.EnvironmentVariableService.Save(ctx.Request.Context(), &req) + if err != nil { + ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to save environment variable: %w", err)) + return + } + + ctx.Status(201) +} + +// DeleteEnvironmentVariable godoc +// +// @Tags envVar +// @Summary Delete environment variable +// @Description Delete environment variable +// @Param key path string true "Environment Variable Key" +// @Success 204 +// @Router /env/{key} [delete] +// +// @id DeleteEnvironmentVariable +func DeleteEnvironmentVariable(ctx *gin.Context) { + envVarKey := ctx.Param("key") + + server := server.GetInstance(nil) + + err := server.EnvironmentVariableService.Delete(ctx.Request.Context(), envVarKey) + if err != nil { + if stores.IsEnvironmentVariableNotFound(err) { + ctx.Status(204) + return + } + ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to delete environment variable: %w", err)) + return + } + + ctx.Status(204) +} diff --git a/pkg/api/controllers/gitprovider/branches.go b/pkg/api/controllers/gitprovider/branches.go index c5b4bcc4b3..19b67b38f2 100644 --- a/pkg/api/controllers/gitprovider/branches.go +++ b/pkg/api/controllers/gitprovider/branches.go @@ -53,7 +53,7 @@ func GetRepoBranches(ctx *gin.Context) { server := server.GetInstance(nil) - response, err := server.GitProviderService.GetRepoBranches(gitProviderId, namespaceId, repositoryId, options) + response, err := server.GitProviderService.GetRepoBranches(ctx.Request.Context(), gitProviderId, namespaceId, repositoryId, options) if err != nil { statusCode, message, codeErr := controllers.GetHTTPStatusCodeAndMessageFromError(err) if codeErr != nil { diff --git a/pkg/api/controllers/gitprovider/context.go b/pkg/api/controllers/gitprovider/context.go index d43f7f204a..1a933d4bc6 100644 --- a/pkg/api/controllers/gitprovider/context.go +++ b/pkg/api/controllers/gitprovider/context.go @@ -35,7 +35,7 @@ func GetGitContext(ctx *gin.Context) { server := server.GetInstance(nil) - gitProvider, _, err := server.GitProviderService.GetGitProviderForUrl(repositoryContext.Url) + gitProvider, _, err := server.GitProviderService.GetGitProviderForUrl(ctx.Request.Context(), repositoryContext.Url) if err != nil { statusCode, message, codeErr := controllers.GetHTTPStatusCodeAndMessageFromError(err) if codeErr != nil { @@ -78,7 +78,7 @@ func GetUrlFromRepository(ctx *gin.Context) { server := server.GetInstance(nil) - gitProvider, _, err := server.GitProviderService.GetGitProviderForUrl(repoContext.Url) + gitProvider, _, err := server.GitProviderService.GetGitProviderForUrl(ctx.Request.Context(), repoContext.Url) if err != nil { statusCode, message, codeErr := controllers.GetHTTPStatusCodeAndMessageFromError(err) if codeErr != nil { diff --git a/pkg/api/controllers/gitprovider/dto/dto.go b/pkg/api/controllers/gitprovider/dto/dto.go index 9a46b18219..217d058487 100644 --- a/pkg/api/controllers/gitprovider/dto/dto.go +++ b/pkg/api/controllers/gitprovider/dto/dto.go @@ -4,7 +4,7 @@ package dto import ( - "github.com/daytonaio/daytona/pkg/gitprovider" + "github.com/daytonaio/daytona/pkg/models" ) type RepositoryUrl struct { @@ -12,12 +12,12 @@ type RepositoryUrl struct { } // @name RepositoryUrl type SetGitProviderConfig struct { - Id string `json:"id" validate:"optional"` - ProviderId string `json:"providerId" validate:"required"` - Username *string `json:"username,omitempty" validate:"optional"` - Token string `json:"token" validate:"required"` - BaseApiUrl *string `json:"baseApiUrl,omitempty" validate:"optional"` - Alias *string `json:"alias,omitempty" validate:"optional"` - SigningKey *string `json:"signingKey,omitempty" validate:"optional"` - SigningMethod *gitprovider.SigningMethod `json:"signingMethod,omitempty" validate:"optional"` + Id string `json:"id" validate:"optional"` + ProviderId string `json:"providerId" validate:"required"` + Username *string `json:"username,omitempty" validate:"optional"` + Token string `json:"token" validate:"required"` + BaseApiUrl *string `json:"baseApiUrl,omitempty" validate:"optional"` + Alias *string `json:"alias,omitempty" validate:"optional"` + SigningKey *string `json:"signingKey,omitempty" validate:"optional"` + SigningMethod *models.SigningMethod `json:"signingMethod,omitempty" validate:"optional"` } // @name SetGitProviderConfig diff --git a/pkg/api/controllers/gitprovider/gitprovider.go b/pkg/api/controllers/gitprovider/gitprovider.go index 004422b20f..9b406361e6 100644 --- a/pkg/api/controllers/gitprovider/gitprovider.go +++ b/pkg/api/controllers/gitprovider/gitprovider.go @@ -13,8 +13,8 @@ import ( "github.com/daytonaio/daytona/pkg/api/controllers" "github.com/daytonaio/daytona/pkg/api/controllers/gitprovider/dto" - "github.com/daytonaio/daytona/pkg/apikey" "github.com/daytonaio/daytona/pkg/gitprovider" + "github.com/daytonaio/daytona/pkg/models" "github.com/daytonaio/daytona/pkg/server" "github.com/gin-gonic/gin" ) @@ -25,16 +25,16 @@ import ( // @Summary List Git providers // @Description List Git providers // @Produce json -// @Success 200 {array} gitprovider.GitProviderConfig +// @Success 200 {array} models.GitProviderConfig // @Router /gitprovider [get] // // @id ListGitProviders func ListGitProviders(ctx *gin.Context) { - var response []*gitprovider.GitProviderConfig + var response []*models.GitProviderConfig server := server.GetInstance(nil) - response, err := server.GitProviderService.ListConfigs() + response, err := server.GitProviderService.ListConfigs(ctx.Request.Context()) if err != nil { ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to list git providers: %w", err)) return @@ -55,7 +55,7 @@ func ListGitProviders(ctx *gin.Context) { // @Description List Git providers for url // @Produce json // @Param url path string true "Url" -// @Success 200 {array} gitprovider.GitProviderConfig +// @Success 200 {array} models.GitProviderConfig // @Router /gitprovider/for-url/{url} [get] // // @id ListGitProvidersForUrl @@ -70,14 +70,14 @@ func ListGitProvidersForUrl(ctx *gin.Context) { server := server.GetInstance(nil) - gitProviders, err := server.GitProviderService.ListConfigsForUrl(decodedUrl) + gitProviders, err := server.GitProviderService.ListConfigsForUrl(ctx.Request.Context(), decodedUrl) if err != nil { ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to get git provider for url: %w", err)) return } apiKeyType, ok := ctx.Get("apiKeyType") - if !ok || apiKeyType == apikey.ApiKeyTypeClient { + if !ok || apiKeyType == models.ApiKeyTypeClient { for _, gitProvider := range gitProviders { gitProvider.Token = "" } @@ -86,23 +86,23 @@ func ListGitProvidersForUrl(ctx *gin.Context) { ctx.JSON(200, gitProviders) } -// GetGitProvider godoc +// FindGitProvider godoc // // @Tags gitProvider -// @Summary Get Git provider -// @Description Get Git provider +// @Summary Find Git provider +// @Description Find Git provider // @Produce plain // @Param gitProviderId path string true "ID" -// @Success 200 {object} gitprovider.GitProviderConfig +// @Success 200 {object} models.GitProviderConfig // @Router /gitprovider/{gitProviderId} [get] // -// @id GetGitProvider -func GetGitProvider(ctx *gin.Context) { +// @id FindGitProvider +func FindGitProvider(ctx *gin.Context) { id := ctx.Param("gitProviderId") server := server.GetInstance(nil) - gitProvider, err := server.GitProviderService.GetConfig(id) + gitProvider, err := server.GitProviderService.FindConfig(ctx.Request.Context(), id) if err != nil { statusCode, message, codeErr := controllers.GetHTTPStatusCodeAndMessageFromError(err) if codeErr != nil { @@ -113,25 +113,25 @@ func GetGitProvider(ctx *gin.Context) { } apiKeyType, ok := ctx.Get("apiKeyType") - if !ok || apiKeyType == apikey.ApiKeyTypeClient { + if !ok || apiKeyType == models.ApiKeyTypeClient { gitProvider.Token = "" } ctx.JSON(200, gitProvider) } -// GetGitProviderIdForUrl godoc +// FindGitProviderIdForUrl godoc // // @Tags gitProvider -// @Summary Get Git provider ID -// @Description Get Git provider ID +// @Summary Find Git provider ID +// @Description Find Git provider ID // @Produce plain // @Param url path string true "Url" // @Success 200 {string} providerId // @Router /gitprovider/id-for-url/{url} [get] // -// @id GetGitProviderIdForUrl -func GetGitProviderIdForUrl(ctx *gin.Context) { +// @id FindGitProviderIdForUrl +func FindGitProviderIdForUrl(ctx *gin.Context) { urlParam := ctx.Param("url") decodedUrl, err := url.QueryUnescape(urlParam) @@ -142,7 +142,7 @@ func GetGitProviderIdForUrl(ctx *gin.Context) { server := server.GetInstance(nil) - _, providerId, err := server.GitProviderService.GetGitProviderForUrl(decodedUrl) + _, providerId, err := server.GitProviderService.GetGitProviderForUrl(ctx.Request.Context(), decodedUrl) if err != nil { statusCode, message, codeErr := controllers.GetHTTPStatusCodeAndMessageFromError(err) if codeErr != nil { @@ -155,18 +155,18 @@ func GetGitProviderIdForUrl(ctx *gin.Context) { ctx.String(200, providerId) } -// SetGitProvider godoc +// SaveGitProvider godoc // // @Tags gitProvider -// @Summary Set Git provider -// @Description Set Git provider +// @Summary Save Git provider +// @Description Save Git provider // @Param gitProviderConfig body SetGitProviderConfig true "Git provider" // @Produce json // @Success 200 // @Router /gitprovider [put] // -// @id SetGitProvider -func SetGitProvider(ctx *gin.Context) { +// @id SaveGitProvider +func SaveGitProvider(ctx *gin.Context) { var setConfigDto dto.SetGitProviderConfig err := ctx.BindJSON(&setConfigDto) @@ -175,7 +175,7 @@ func SetGitProvider(ctx *gin.Context) { return } - gitProviderConfig := gitprovider.GitProviderConfig{ + gitProviderConfig := models.GitProviderConfig{ Id: setConfigDto.Id, ProviderId: setConfigDto.ProviderId, Token: setConfigDto.Token, @@ -194,7 +194,7 @@ func SetGitProvider(ctx *gin.Context) { server := server.GetInstance(nil) - err = server.GitProviderService.SetGitProviderConfig(&gitProviderConfig) + err = server.GitProviderService.SaveConfig(ctx.Request.Context(), &gitProviderConfig) if err != nil { statusCode, message, codeErr := controllers.GetHTTPStatusCodeAndMessageFromError(err) if codeErr != nil { @@ -207,23 +207,23 @@ func SetGitProvider(ctx *gin.Context) { ctx.JSON(200, nil) } -// RemoveGitProvider godoc +// DeleteGitProvider godoc // // @Tags gitProvider -// @Summary Remove Git provider -// @Description Remove Git provider +// @Summary Delete Git provider +// @Description Delete Git provider // @Param gitProviderId path string true "Git provider" // @Produce json // @Success 200 // @Router /gitprovider/{gitProviderId} [delete] // -// @id RemoveGitProvider -func RemoveGitProvider(ctx *gin.Context) { +// @id DeleteGitProvider +func DeleteGitProvider(ctx *gin.Context) { gitProviderId := ctx.Param("gitProviderId") server := server.GetInstance(nil) - err := server.GitProviderService.RemoveGitProvider(gitProviderId) + err := server.GitProviderService.DeleteConfig(ctx.Request.Context(), gitProviderId) if err != nil { statusCode, message, codeErr := controllers.GetHTTPStatusCodeAndMessageFromError(err) if codeErr != nil { diff --git a/pkg/api/controllers/gitprovider/namespaces.go b/pkg/api/controllers/gitprovider/namespaces.go index d78c092fc8..433c2c6440 100644 --- a/pkg/api/controllers/gitprovider/namespaces.go +++ b/pkg/api/controllers/gitprovider/namespaces.go @@ -37,7 +37,7 @@ func GetNamespaces(ctx *gin.Context) { server := server.GetInstance(nil) - response, err := server.GitProviderService.GetNamespaces(gitProviderId, options) + response, err := server.GitProviderService.GetNamespaces(ctx.Request.Context(), gitProviderId, options) if err != nil { statusCode, message, codeErr := controllers.GetHTTPStatusCodeAndMessageFromError(err) if codeErr != nil { diff --git a/pkg/api/controllers/gitprovider/pull_requests.go b/pkg/api/controllers/gitprovider/pull_requests.go index ef5a079bed..367d47cb98 100644 --- a/pkg/api/controllers/gitprovider/pull_requests.go +++ b/pkg/api/controllers/gitprovider/pull_requests.go @@ -53,7 +53,7 @@ func GetRepoPRs(ctx *gin.Context) { server := server.GetInstance(nil) - response, err := server.GitProviderService.GetRepoPRs(gitProviderId, namespaceId, repositoryId, options) + response, err := server.GitProviderService.GetRepoPRs(ctx.Request.Context(), gitProviderId, namespaceId, repositoryId, options) if err != nil { statusCode, message, codeErr := controllers.GetHTTPStatusCodeAndMessageFromError(err) if codeErr != nil { diff --git a/pkg/api/controllers/gitprovider/repositories.go b/pkg/api/controllers/gitprovider/repositories.go index 8c7eb8fb94..ccd5d5963c 100644 --- a/pkg/api/controllers/gitprovider/repositories.go +++ b/pkg/api/controllers/gitprovider/repositories.go @@ -38,7 +38,7 @@ func GetRepositories(ctx *gin.Context) { server := server.GetInstance(nil) - response, err := server.GitProviderService.GetRepositories(gitProviderId, namespaceId, options) + response, err := server.GitProviderService.GetRepositories(ctx.Request.Context(), gitProviderId, namespaceId, options) if err != nil { statusCode, message, codeErr := controllers.GetHTTPStatusCodeAndMessageFromError(err) if codeErr != nil { diff --git a/pkg/api/controllers/gitprovider/user.go b/pkg/api/controllers/gitprovider/user.go index 23b85ac95d..2b105e9e8f 100644 --- a/pkg/api/controllers/gitprovider/user.go +++ b/pkg/api/controllers/gitprovider/user.go @@ -27,7 +27,7 @@ func GetGitUser(ctx *gin.Context) { server := server.GetInstance(nil) - response, err := server.GitProviderService.GetGitUser(gitProviderId) + response, err := server.GitProviderService.GetGitUser(ctx.Request.Context(), gitProviderId) if err != nil { statusCode, message, codeErr := controllers.GetHTTPStatusCodeAndMessageFromError(err) if codeErr != nil { diff --git a/pkg/api/controllers/job/job.go b/pkg/api/controllers/job/job.go new file mode 100644 index 0000000000..077f76b62a --- /dev/null +++ b/pkg/api/controllers/job/job.go @@ -0,0 +1,75 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package job + +import ( + "fmt" + "net/http" + + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/server" + "github.com/daytonaio/daytona/pkg/stores" + "github.com/gin-gonic/gin" +) + +// ListJobs godoc +// +// @Tags job +// @Summary List jobs +// @Description List jobs +// @Param states query []string false "Job States" collectionFormat(multi) +// @Param actions query []string false "Job Actions" collectionFormat(multi) +// @Param resourceId query string false "Resource ID" +// @Param resourceType query string false "Resource Type" +// @Produce json +// @Success 200 {array} Job +// @Router /job [get] +// +// @id ListJobs +func ListJobs(ctx *gin.Context) { + states := ctx.QueryArray("states") + var jobStates *[]models.JobState + if len(states) > 0 { + jobStates = &[]models.JobState{} + for _, s := range states { + *jobStates = append(*jobStates, models.JobState(s)) + } + } + + resourceIdQuery := ctx.Query("resourceId") + var resourceId *string + if resourceIdQuery != "" { + resourceId = &resourceIdQuery + } + + resourceTypeQuery := ctx.Query("resourceType") + var resourceType *models.ResourceType + if resourceTypeQuery != "" { + resourceType = (*models.ResourceType)(&resourceTypeQuery) + } + + actions := ctx.QueryArray("actions") + var jobActions *[]models.JobAction + if len(actions) > 0 { + jobActions = &[]models.JobAction{} + for _, a := range actions { + *jobActions = append(*jobActions, models.JobAction(a)) + } + } + + server := server.GetInstance(nil) + + jobs, err := server.JobService.List(ctx.Request.Context(), &stores.JobFilter{ + States: jobStates, + ResourceId: resourceId, + ResourceType: resourceType, + Actions: jobActions, + }) + if err != nil { + ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to list jobs: %s", err.Error())) + return + } + + ctx.JSON(200, jobs) +} diff --git a/pkg/api/controllers/log/websocket.go b/pkg/api/controllers/log/read.go similarity index 56% rename from pkg/api/controllers/log/websocket.go rename to pkg/api/controllers/log/read.go index e5c23f2c0d..2932e48af7 100644 --- a/pkg/api/controllers/log/websocket.go +++ b/pkg/api/controllers/log/read.go @@ -10,7 +10,7 @@ import ( "net/http" "time" - "github.com/daytonaio/daytona/internal/util" + "github.com/daytonaio/daytona/pkg/logs" "github.com/daytonaio/daytona/pkg/server" "github.com/gin-gonic/gin" "github.com/gorilla/websocket" @@ -25,105 +25,22 @@ var upgrader = websocket.Upgrader{ }, } -func writeToWs(ws *websocket.Conn, c chan []byte, errChan chan error) { - for { - err := ws.WriteMessage(websocket.TextMessage, <-c) - if err != nil { - errChan <- err - break - } - } -} - -func writeJSONToWs(ws *websocket.Conn, c chan interface{}, errChan chan error) { - for { - err := ws.WriteJSON(<-c) - if err != nil { - errChan <- err - break - } - } -} - -// ReadLog reads from the logReader and writes to the websocket. -// T is the type of the message to be read from the logReader -func ReadLog[T any](ginCtx *gin.Context, logReader io.Reader, readFunc func(context.Context, io.Reader, bool, chan T, chan error), wsWriteFunc func(*websocket.Conn, chan T, chan error)) { - followQuery := ginCtx.Query("follow") - follow := followQuery == "true" - - ws, err := upgrader.Upgrade(ginCtx.Writer, ginCtx.Request, nil) - if err != nil { - log.Error(err) - return - } - - defer func() { - closeErr := websocket.CloseNormalClosure - if !errors.Is(err, io.EOF) { - closeErr = websocket.CloseInternalServerErr - } - err := ws.WriteControl(websocket.CloseMessage, websocket.FormatCloseMessage(closeErr, ""), time.Now().Add(time.Second)) - if err != nil { - log.Trace(err) - } - ws.Close() - }() - - msgChannel := make(chan T) - errChannel := make(chan error) - ctx, cancel := context.WithCancel(ginCtx.Request.Context()) - - defer cancel() - go readFunc(ctx, logReader, follow, msgChannel, errChannel) - go wsWriteFunc(ws, msgChannel, errChannel) - - readErr := make(chan error) - go func() { - for { - _, _, err := ws.ReadMessage() - readErr <- err - } - }() - - for { - select { - case <-ctx.Done(): - return - case err = <-errChannel: - if err != nil { - if !errors.Is(err, io.EOF) { - log.Error(err) - } - cancel() - return - } - case err := <-readErr: - if websocket.IsUnexpectedCloseError(err, websocket.CloseNormalClosure, websocket.CloseAbnormalClosure) { - log.Error(err) - } - if err != nil { - return - } - } - } -} - -func ReadServerLog(ginCtx *gin.Context) { +func ReadServerLog(ctx *gin.Context) { s := server.GetInstance(nil) - logFileQuery := ginCtx.Query("file") - retryQuery := ginCtx.DefaultQuery("retry", "true") + logFileQuery := ctx.Query("file") + retryQuery := ctx.DefaultQuery("retry", "true") retry := retryQuery == "true" if retry { for { reader, err := s.GetLogReader(logFileQuery) if err != nil && server.IsLogFileNotFound(err) { - ginCtx.AbortWithError(http.StatusNotFound, err) + ctx.AbortWithError(http.StatusNotFound, err) return } if err == nil { - ReadLog(ginCtx, reader, util.ReadLog, writeToWs) + ReadLog(ctx, reader, logs.ReadLog, writeToWs) return } time.Sleep(TIMEOUT) @@ -133,95 +50,204 @@ func ReadServerLog(ginCtx *gin.Context) { reader, err := s.GetLogReader(logFileQuery) if err != nil { if server.IsLogFileNotFound(err) { - ginCtx.AbortWithError(http.StatusNotFound, err) + ctx.AbortWithError(http.StatusNotFound, err) return } - ginCtx.AbortWithError(http.StatusInternalServerError, err) + ctx.AbortWithError(http.StatusInternalServerError, err) return } - ReadLog(ginCtx, reader, util.ReadLog, writeToWs) + ReadLog(ctx, reader, logs.ReadLog, writeToWs) } -func ReadWorkspaceLog(ginCtx *gin.Context) { - workspaceId := ginCtx.Param("workspaceId") - retryQuery := ginCtx.DefaultQuery("retry", "true") +func ReadTargetLog(ctx *gin.Context) { + targetId := ctx.Param("targetId") + retryQuery := ctx.DefaultQuery("retry", "true") retry := retryQuery == "true" server := server.GetInstance(nil) if retry { for { - wsLogReader, err := server.WorkspaceService.GetWorkspaceLogReader(workspaceId) + targetLogReader, err := server.TargetService.GetTargetLogReader(ctx.Request.Context(), targetId) if err == nil { - ReadLog(ginCtx, wsLogReader, util.ReadJSONLog, writeJSONToWs) + ReadLog(ctx, targetLogReader, logs.ReadJSONLog, writeJSONToWs) return } time.Sleep(TIMEOUT) } } - wsLogReader, err := server.WorkspaceService.GetWorkspaceLogReader(workspaceId) + targetLogReader, err := server.TargetService.GetTargetLogReader(ctx.Request.Context(), targetId) if err != nil { - ginCtx.AbortWithError(http.StatusInternalServerError, err) + ctx.AbortWithError(http.StatusInternalServerError, err) return } - ReadLog(ginCtx, wsLogReader, util.ReadJSONLog, writeJSONToWs) + ReadLog(ctx, targetLogReader, logs.ReadJSONLog, writeJSONToWs) } -func ReadProjectLog(ginCtx *gin.Context) { - workspaceId := ginCtx.Param("workspaceId") - projectName := ginCtx.Param("projectName") - retryQuery := ginCtx.DefaultQuery("retry", "true") +func ReadWorkspaceLog(ctx *gin.Context) { + workspaceId := ctx.Param("workspaceId") + retryQuery := ctx.DefaultQuery("retry", "true") retry := retryQuery == "true" server := server.GetInstance(nil) if retry { for { - projectLogReader, err := server.WorkspaceService.GetProjectLogReader(workspaceId, projectName) + workspaceLogReader, err := server.WorkspaceService.GetWorkspaceLogReader(ctx.Request.Context(), workspaceId) if err == nil { - ReadLog(ginCtx, projectLogReader, util.ReadJSONLog, writeJSONToWs) + ReadLog(ctx, workspaceLogReader, logs.ReadJSONLog, writeJSONToWs) return } time.Sleep(TIMEOUT) } } - projectLogReader, err := server.WorkspaceService.GetProjectLogReader(workspaceId, projectName) + workspaceLogReader, err := server.WorkspaceService.GetWorkspaceLogReader(ctx.Request.Context(), workspaceId) if err != nil { - ginCtx.AbortWithError(http.StatusInternalServerError, err) + ctx.AbortWithError(http.StatusInternalServerError, err) return } - ReadLog(ginCtx, projectLogReader, util.ReadJSONLog, writeJSONToWs) + ReadLog(ctx, workspaceLogReader, logs.ReadJSONLog, writeJSONToWs) } -func ReadBuildLog(ginCtx *gin.Context) { - buildId := ginCtx.Param("buildId") - retryQuery := ginCtx.DefaultQuery("retry", "true") +func ReadBuildLog(ctx *gin.Context) { + buildId := ctx.Param("buildId") + retryQuery := ctx.DefaultQuery("retry", "true") retry := retryQuery == "true" server := server.GetInstance(nil) if retry { for { - buildLogReader, err := server.BuildService.GetBuildLogReader(buildId) + buildLogReader, err := server.BuildService.GetBuildLogReader(ctx.Request.Context(), buildId) if err == nil { - ReadLog(ginCtx, buildLogReader, util.ReadJSONLog, writeJSONToWs) + ReadLog(ctx, buildLogReader, logs.ReadJSONLog, writeJSONToWs) return } time.Sleep(TIMEOUT) } } - buildLogReader, err := server.BuildService.GetBuildLogReader(buildId) + buildLogReader, err := server.BuildService.GetBuildLogReader(ctx.Request.Context(), buildId) if err != nil { - ginCtx.AbortWithError(http.StatusInternalServerError, err) + ctx.AbortWithError(http.StatusInternalServerError, err) return } - ReadLog(ginCtx, buildLogReader, util.ReadJSONLog, writeJSONToWs) + ReadLog(ctx, buildLogReader, logs.ReadJSONLog, writeJSONToWs) +} + +func ReadRunnerLog(ctx *gin.Context) { + runnerId := ctx.Param("runnerId") + retryQuery := ctx.DefaultQuery("retry", "true") + retry := retryQuery == "true" + + server := server.GetInstance(nil) + + if retry { + for { + runnerLogReader, err := server.RunnerService.GetRunnerLogReader(ctx.Request.Context(), runnerId) + if err == nil { + ReadLog(ctx, runnerLogReader, logs.ReadJSONLog, writeJSONToWs) + return + } + time.Sleep(TIMEOUT) + } + } + + runnerLogReader, err := server.RunnerService.GetRunnerLogReader(ctx.Request.Context(), runnerId) + if err != nil { + ctx.AbortWithError(http.StatusInternalServerError, err) + return + } + + ReadLog(ctx, runnerLogReader, logs.ReadJSONLog, writeJSONToWs) +} + +func writeToWs(ws *websocket.Conn, c chan []byte, errChan chan error) { + for { + err := ws.WriteMessage(websocket.TextMessage, <-c) + if err != nil { + errChan <- err + break + } + } +} + +func writeJSONToWs(ws *websocket.Conn, c chan interface{}, errChan chan error) { + for { + err := ws.WriteJSON(<-c) + if err != nil { + errChan <- err + break + } + } +} + +// ReadLog reads from the logReader and writes to the websocket. +// T is the type of the message to be read from the logReader +func ReadLog[T any](ginCtx *gin.Context, logReader io.Reader, readFunc func(context.Context, io.Reader, bool, chan T, chan error), wsWriteFunc func(*websocket.Conn, chan T, chan error)) { + followQuery := ginCtx.Query("follow") + follow := followQuery == "true" + + ws, err := upgrader.Upgrade(ginCtx.Writer, ginCtx.Request, nil) + if err != nil { + log.Error(err) + return + } + + defer func() { + closeErr := websocket.CloseNormalClosure + if !errors.Is(err, io.EOF) { + closeErr = websocket.CloseInternalServerErr + } + err := ws.WriteControl(websocket.CloseMessage, websocket.FormatCloseMessage(closeErr, ""), time.Now().Add(time.Second)) + if err != nil { + log.Trace(err) + } + ws.Close() + }() + + msgChannel := make(chan T) + errChannel := make(chan error) + ctx, cancel := context.WithCancel(ginCtx.Request.Context()) + + defer cancel() + go readFunc(ctx, logReader, follow, msgChannel, errChannel) + go wsWriteFunc(ws, msgChannel, errChannel) + + readErr := make(chan error) + go func() { + for { + _, _, err := ws.ReadMessage() + readErr <- err + } + }() + + for { + select { + case <-ctx.Done(): + return + case err = <-errChannel: + if err != nil { + if !errors.Is(err, io.EOF) { + log.Error(err) + } + cancel() + return + } + case err := <-readErr: + if websocket.IsUnexpectedCloseError(err, websocket.CloseNormalClosure, websocket.CloseAbnormalClosure) { + log.Error(err) + } + if err != nil { + return + } + } + } } diff --git a/pkg/api/controllers/log/write.go b/pkg/api/controllers/log/write.go new file mode 100644 index 0000000000..e71a771f62 --- /dev/null +++ b/pkg/api/controllers/log/write.go @@ -0,0 +1,142 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package log + +import ( + "context" + "errors" + "fmt" + "io" + "net/http" + "time" + + "github.com/daytonaio/daytona/pkg/server" + "github.com/gin-gonic/gin" + "github.com/gorilla/websocket" + log "github.com/sirupsen/logrus" +) + +func WriteWorkspaceLog(ctx *gin.Context) { + workspaceId := ctx.Param("workspaceId") + + server := server.GetInstance(nil) + + logWriter, err := server.WorkspaceService.GetWorkspaceLogWriter(ctx, workspaceId) + if err != nil { + ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to get workspace log writer: %w", err)) + return + } + defer logWriter.Close() + + writeLog(ctx, logWriter) +} + +func WriteTargetLog(ctx *gin.Context) { + targetId := ctx.Param("targetId") + + server := server.GetInstance(nil) + + logWriter, err := server.TargetService.GetTargetLogWriter(ctx, targetId) + if err != nil { + ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to get target log writer: %w", err)) + return + } + defer logWriter.Close() + + writeLog(ctx, logWriter) +} + +func WriteBuildLog(ctx *gin.Context) { + buildId := ctx.Param("buildId") + + server := server.GetInstance(nil) + + logWriter, err := server.BuildService.GetBuildLogWriter(ctx, buildId) + if err != nil { + ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to get build log writer: %w", err)) + return + } + defer logWriter.Close() + + writeLog(ctx, logWriter) +} + +func WriteRunnerLog(ctx *gin.Context) { + runnerId := ctx.Param("runnerId") + + server := server.GetInstance(nil) + + logWriter, err := server.RunnerService.GetRunnerLogWriter(ctx, runnerId) + if err != nil { + ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to get runner log writer: %w", err)) + return + } + defer logWriter.Close() + + writeLog(ctx, logWriter) +} + +func writeLog(ginCtx *gin.Context, logWriter io.WriteCloser) { + ws, err := upgrader.Upgrade(ginCtx.Writer, ginCtx.Request, nil) + if err != nil { + log.Error(err) + return + } + + defer func() { + closeErr := websocket.CloseNormalClosure + if !errors.Is(err, io.EOF) { + closeErr = websocket.CloseInternalServerErr + } + err := ws.WriteControl(websocket.CloseMessage, websocket.FormatCloseMessage(closeErr, ""), time.Now().Add(time.Second)) + if err != nil { + log.Trace(err) + } + ws.Close() + }() + + errChannel := make(chan error) + ctx, cancel := context.WithCancel(ginCtx.Request.Context()) + + defer cancel() + + readErr := make(chan error) + go func() { + for { + _, msg, err := ws.ReadMessage() + if err != nil { + readErr <- err + return + } + + _, err = logWriter.Write(msg) + if err != nil { + readErr <- err + return + } + } + }() + + for { + select { + case <-ctx.Done(): + return + case err = <-errChannel: + if err != nil { + if !errors.Is(err, io.EOF) { + log.Error(err) + } + cancel() + return + } + case err := <-readErr: + if websocket.IsUnexpectedCloseError(err, websocket.CloseNormalClosure, websocket.CloseAbnormalClosure) { + log.Error(err) + } + if err != nil { + return + } + } + } +} diff --git a/pkg/api/controllers/profiledata/profile_data.go b/pkg/api/controllers/profiledata/profile_data.go deleted file mode 100644 index 1101a96fe2..0000000000 --- a/pkg/api/controllers/profiledata/profile_data.go +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package profiledata - -import ( - "fmt" - "net/http" - - "github.com/daytonaio/daytona/pkg/profiledata" - "github.com/daytonaio/daytona/pkg/server" - "github.com/gin-gonic/gin" -) - -// GetProfileData godoc -// -// @Tags profile -// @Summary Get profile data -// @Description Get profile data -// @Accept json -// @Success 200 {object} profiledata.ProfileData -// @Router /profile [get] -// -// @id GetProfileData -func GetProfileData(ctx *gin.Context) { - server := server.GetInstance(nil) - profileData, err := server.ProfileDataService.Get() - if err != nil { - if profiledata.IsProfileDataNotFound(err) { - ctx.JSON(200, &profiledata.ProfileData{}) - return - } - ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to get profile data: %w", err)) - return - } - - ctx.JSON(200, profileData) -} - -// SetProfileData godoc -// -// @Tags profile -// @Summary Set profile data -// @Description Set profile data -// @Accept json -// @Param profileData body profiledata.ProfileData true "Profile data" -// @Success 201 -// @Router /profile [put] -// -// @id SetProfileData -func SetProfileData(ctx *gin.Context) { - var req profiledata.ProfileData - err := ctx.BindJSON(&req) - if err != nil { - ctx.AbortWithError(http.StatusBadRequest, fmt.Errorf("invalid request body: %w", err)) - return - } - - server := server.GetInstance(nil) - err = server.ProfileDataService.Save(&req) - if err != nil { - ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to save profile data: %w", err)) - return - } - - ctx.Status(201) -} - -// DeleteProfileData godoc -// -// @Tags profile -// @Summary Delete profile data -// @Description Delete profile data -// @Success 204 -// @Router /profile [delete] -// -// @id DeleteProfileData -func DeleteProfileData(ctx *gin.Context) { - server := server.GetInstance(nil) - err := server.ProfileDataService.Delete() - if err != nil { - if profiledata.IsProfileDataNotFound(err) { - ctx.Status(204) - return - } - ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to get profile data: %w", err)) - return - } - - ctx.Status(204) -} diff --git a/pkg/api/controllers/projectconfig/prebuild/prebuild.go b/pkg/api/controllers/projectconfig/prebuild/prebuild.go deleted file mode 100644 index 6bc2881f37..0000000000 --- a/pkg/api/controllers/projectconfig/prebuild/prebuild.go +++ /dev/null @@ -1,181 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package prebuild - -import ( - "errors" - "fmt" - "net/http" - "strconv" - - "github.com/daytonaio/daytona/pkg/server" - "github.com/daytonaio/daytona/pkg/server/projectconfig/dto" - "github.com/daytonaio/daytona/pkg/workspace/project/config" - "github.com/gin-gonic/gin" -) - -// GetPrebuild godoc -// -// @Tags prebuild -// @Summary Get prebuild -// @Description Get prebuild -// @Accept json -// @Param configName path string true "Project config name" -// @Param prebuildId path string true "Prebuild ID" -// @Success 200 {object} PrebuildDTO -// @Router /project-config/{configName}/prebuild/{prebuildId} [get] -// -// @id GetPrebuild -func GetPrebuild(ctx *gin.Context) { - configName := ctx.Param("configName") - prebuildId := ctx.Param("prebuildId") - - server := server.GetInstance(nil) - res, err := server.ProjectConfigService.FindPrebuild(&config.ProjectConfigFilter{ - Name: &configName, - }, &config.PrebuildFilter{ - Id: &prebuildId, - }) - if err != nil { - if config.IsPrebuildNotFound(err) { - ctx.AbortWithError(http.StatusNotFound, errors.New("prebuild not found")) - return - } - ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to get prebuild: %s", err.Error())) - return - } - - ctx.JSON(200, res) -} - -// SetPrebuild godoc - -// @Tags prebuild -// @Summary Set prebuild -// @Description Set prebuild -// @Accept json -// @Param configName path string true "Config name" -// @Param prebuild body CreatePrebuildDTO true "Prebuild" -// @Success 201 {string} prebuildId -// @Router /project-config/{configName}/prebuild [put] -// -// @id SetPrebuild -func SetPrebuild(ctx *gin.Context) { - configName := ctx.Param("configName") - - var dto dto.CreatePrebuildDTO - err := ctx.BindJSON(&dto) - if err != nil { - ctx.AbortWithError(http.StatusBadRequest, fmt.Errorf("invalid request body: %s", err.Error())) - return - } - - server := server.GetInstance(nil) - prebuild, err := server.ProjectConfigService.SetPrebuild(configName, dto) - if err != nil { - ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to set prebuild: %s", err.Error())) - return - } - - ctx.String(201, prebuild.Id) -} - -// ListPrebuilds godoc - -// @Tags prebuild -// @Summary List prebuilds -// @Description List prebuilds -// @Accept json -// @Success 200 {array} PrebuildDTO -// @Router /project-config/prebuild [get] -// -// @id ListPrebuilds -func ListPrebuilds(ctx *gin.Context) { - server := server.GetInstance(nil) - res, err := server.ProjectConfigService.ListPrebuilds(nil, nil) - if err != nil { - ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to get prebuilds: %s", err.Error())) - return - } - - ctx.JSON(200, res) -} - -// ListPrebuildsForProjectConfig godoc - -// @Tags prebuild -// @Summary List prebuilds for project config -// @Description List prebuilds for project config -// @Accept json -// @Param configName path string true "Config name" -// @Success 200 {array} PrebuildDTO -// @Router /project-config/{configName}/prebuild [get] -// -// @id ListPrebuildsForProjectConfig -func ListPrebuildsForProjectConfig(ctx *gin.Context) { - configName := ctx.Param("configName") - - var projectConfigFilter *config.ProjectConfigFilter - - if configName != "" { - projectConfigFilter = &config.ProjectConfigFilter{ - Name: &configName, - } - } - - server := server.GetInstance(nil) - res, err := server.ProjectConfigService.ListPrebuilds(projectConfigFilter, nil) - if err != nil { - ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to get prebuilds: %s", err.Error())) - return - } - - ctx.JSON(200, res) -} - -// DeletePrebuild godoc -// -// @Tags prebuild -// @Summary Delete prebuild -// @Description Delete prebuild -// @Accept json -// @Param configName path string true "Project config name" -// @Param prebuildId path string true "Prebuild ID" -// @Param force query bool false "Force" -// @Success 204 -// @Router /project-config/{configName}/prebuild/{prebuildId} [delete] -// -// @id DeletePrebuild -func DeletePrebuild(ctx *gin.Context) { - configName := ctx.Param("configName") - prebuildId := ctx.Param("prebuildId") - forceQuery := ctx.Query("force") - - var err error - var force bool - - if forceQuery != "" { - force, err = strconv.ParseBool(forceQuery) - if err != nil { - ctx.AbortWithError(http.StatusBadRequest, errors.New("invalid value for force flag")) - return - } - } - - server := server.GetInstance(nil) - errs := server.ProjectConfigService.DeletePrebuild(configName, prebuildId, force) - if len(errs) > 0 { - if config.IsPrebuildNotFound(errs[0]) { - ctx.AbortWithError(http.StatusNotFound, errors.New("prebuild not found")) - return - } - for _, err := range errs { - _ = ctx.Error(err) - } - ctx.AbortWithStatus(http.StatusInternalServerError) - return - } - - ctx.Status(204) -} diff --git a/pkg/api/controllers/projectconfig/project_config.go b/pkg/api/controllers/projectconfig/project_config.go deleted file mode 100644 index 15d7584ee0..0000000000 --- a/pkg/api/controllers/projectconfig/project_config.go +++ /dev/null @@ -1,218 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package projectconfig - -import ( - "errors" - "fmt" - "net/http" - "net/url" - "strconv" - - "github.com/daytonaio/daytona/internal/util" - "github.com/daytonaio/daytona/internal/util/apiclient/conversion" - "github.com/daytonaio/daytona/pkg/server" - "github.com/daytonaio/daytona/pkg/server/projectconfig/dto" - "github.com/daytonaio/daytona/pkg/workspace/project/config" - "github.com/gin-gonic/gin" - log "github.com/sirupsen/logrus" -) - -// GetProjectConfig godoc -// -// @Tags project-config -// @Summary Get project config data -// @Description Get project config data -// @Accept json -// @Param configName path string true "Config name" -// @Success 200 {object} ProjectConfig -// @Router /project-config/{configName} [get] -// -// @id GetProjectConfig -func GetProjectConfig(ctx *gin.Context) { - configName := ctx.Param("configName") - - server := server.GetInstance(nil) - - projectConfig, err := server.ProjectConfigService.Find(&config.ProjectConfigFilter{ - Name: &configName, - }) - if err != nil { - ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to get project config: %s", err.Error())) - return - } - - ctx.JSON(200, projectConfig) -} - -// GetDefaultProjectConfig godoc -// -// @Tags project-config -// @Summary Get project configs by git url -// @Description Get project configs by git url -// @Produce json -// @Param gitUrl path string true "Git URL" -// @Success 200 {object} ProjectConfig -// @Router /project-config/default/{gitUrl} [get] -// -// @id GetDefaultProjectConfig -func GetDefaultProjectConfig(ctx *gin.Context) { - gitUrl := ctx.Param("gitUrl") - - decodedURLParam, err := url.QueryUnescape(gitUrl) - if err != nil { - ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to decode query param: %s", err.Error())) - return - } - - server := server.GetInstance(nil) - - projectConfigs, err := server.ProjectConfigService.Find(&config.ProjectConfigFilter{ - Url: &decodedURLParam, - Default: util.Pointer(true), - }) - if err != nil { - statusCode := http.StatusInternalServerError - if config.IsProjectConfigNotFound(err) { - statusCode = http.StatusNotFound - ctx.AbortWithStatus(statusCode) - log.Debugf("Project config not added for git url: %s", decodedURLParam) - return - } - ctx.AbortWithError(statusCode, fmt.Errorf("failed to find project config by git url: %s", err.Error())) - return - } - - ctx.JSON(200, projectConfigs) -} - -// ListProjectConfigs godoc -// -// @Tags project-config -// @Summary List project configs -// @Description List project configs -// @Produce json -// @Success 200 {array} ProjectConfig -// @Router /project-config [get] -// -// @id ListProjectConfigs -func ListProjectConfigs(ctx *gin.Context) { - server := server.GetInstance(nil) - - projectConfigs, err := server.ProjectConfigService.List(nil) - if err != nil { - ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to list project configs: %s", err.Error())) - return - } - - ctx.JSON(200, projectConfigs) -} - -// SetProjectConfig godoc -// -// @Tags project-config -// @Summary Set project config data -// @Description Set project config data -// @Accept json -// @Param projectConfig body CreateProjectConfigDTO true "Project config" -// @Success 201 -// @Router /project-config [put] -// -// @id SetProjectConfig -func SetProjectConfig(ctx *gin.Context) { - var req dto.CreateProjectConfigDTO - err := ctx.BindJSON(&req) - if err != nil { - ctx.AbortWithError(http.StatusBadRequest, fmt.Errorf("invalid request body: %s", err.Error())) - return - } - - s := server.GetInstance(nil) - - projectConfig := conversion.ToProjectConfig(req) - - err = s.ProjectConfigService.Save(projectConfig) - if err != nil { - ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to save project config: %s", err.Error())) - return - } - - ctx.Status(201) -} - -// SetDefaultProjectConfig godoc -// -// @Tags project-config -// @Summary Set project config to default -// @Description Set project config to default -// @Param configName path string true "Config name" -// @Success 200 -// @Router /project-config/{configName}/set-default [patch] -// -// @id SetDefaultProjectConfig -func SetDefaultProjectConfig(ctx *gin.Context) { - configName := ctx.Param("configName") - - server := server.GetInstance(nil) - - err := server.ProjectConfigService.SetDefault(configName) - if err != nil { - ctx.AbortWithError(http.StatusNotFound, fmt.Errorf("failed to set project config to default: %s", err.Error())) - return - } - - ctx.Status(200) -} - -// DeleteProjectConfig godoc -// -// @Tags project-config -// @Summary Delete project config data -// @Description Delete project config data -// @Param configName path string true "Config name" -// @Param force query bool false "Force" -// @Success 204 -// @Router /project-config/{configName} [delete] -// -// @id DeleteProjectConfig -func DeleteProjectConfig(ctx *gin.Context) { - configName := ctx.Param("configName") - forceQuery := ctx.Query("force") - - var err error - var force bool - - if forceQuery != "" { - force, err = strconv.ParseBool(forceQuery) - if err != nil { - ctx.AbortWithError(http.StatusBadRequest, errors.New("invalid value for force flag")) - return - } - } - - server := server.GetInstance(nil) - - projectConfig, err := server.ProjectConfigService.Find(&config.ProjectConfigFilter{ - Name: &configName, - }) - if err != nil { - ctx.AbortWithError(http.StatusNotFound, fmt.Errorf("failed to find project config: %s", err.Error())) - return - } - - errs := server.ProjectConfigService.Delete(projectConfig.Name, force) - if len(errs) > 0 { - if config.IsProjectConfigNotFound(errs[0]) { - ctx.AbortWithError(http.StatusNotFound, errors.New("project config not found")) - return - } - for _, err := range errs { - _ = ctx.Error(err) - } - ctx.AbortWithStatus(http.StatusInternalServerError) - return - } - - ctx.Status(204) -} diff --git a/pkg/api/controllers/provider/install.go b/pkg/api/controllers/provider/install.go deleted file mode 100644 index 4cfc8a5d68..0000000000 --- a/pkg/api/controllers/provider/install.go +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package provider - -import ( - "fmt" - "net/http" - - "github.com/daytonaio/daytona/pkg/api/controllers/provider/dto" - "github.com/daytonaio/daytona/pkg/server" - "github.com/gin-gonic/gin" -) - -// InstallProvider godoc -// -// @Tags provider -// @Summary Install a provider -// @Description Install a provider -// @Accept json -// @Param provider body InstallProviderRequest true "Provider to install" -// @Success 200 -// @Router /provider/install [post] -// -// @id InstallProvider -func InstallProvider(ctx *gin.Context) { - var req dto.InstallProviderRequest - err := ctx.BindJSON(&req) - if err != nil { - ctx.AbortWithError(http.StatusBadRequest, fmt.Errorf("invalid request body: %w", err)) - return - } - - server := server.GetInstance(nil) - if _, err := server.ProviderManager.GetProvider(req.Name); err == nil { - err := server.ProviderManager.UninstallProvider(req.Name) - if err != nil { - ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to uninstall current provider: %w", err)) - return - } - } - - downloadPath, err := server.ProviderManager.DownloadProvider(ctx.Request.Context(), req.DownloadUrls, req.Name) - if err != nil { - ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to download provider: %w", err)) - return - } - - err = server.ProviderManager.RegisterProvider(downloadPath, true) - if err != nil { - ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to register provider: %w", err)) - return - } - - ctx.Status(200) -} diff --git a/pkg/api/controllers/provider/list.go b/pkg/api/controllers/provider/list.go deleted file mode 100644 index fe793f3f16..0000000000 --- a/pkg/api/controllers/provider/list.go +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package provider - -import ( - "fmt" - "net/http" - - "github.com/daytonaio/daytona/pkg/api/controllers/provider/dto" - "github.com/daytonaio/daytona/pkg/server" - "github.com/gin-gonic/gin" -) - -// ListProviders godoc -// -// @Tags provider -// @Summary List providers -// @Description List providers -// @Produce json -// @Success 200 {array} dto.Provider -// @Router /provider [get] -// -// @id ListProviders -func ListProviders(ctx *gin.Context) { - server := server.GetInstance(nil) - providers := server.ProviderManager.GetProviders() - - result := []dto.Provider{} - for _, provider := range providers { - info, err := provider.GetInfo() - if err != nil { - ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to get provider: %w", err)) - return - } - - result = append(result, dto.Provider{ - Name: info.Name, - Label: info.Label, - Version: info.Version, - }) - } - - ctx.JSON(200, result) -} diff --git a/pkg/api/controllers/provider/targets.go b/pkg/api/controllers/provider/targets.go deleted file mode 100644 index 173a6e7463..0000000000 --- a/pkg/api/controllers/provider/targets.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package provider - -import ( - "fmt" - "net/http" - - "github.com/daytonaio/daytona/pkg/server" - "github.com/gin-gonic/gin" -) - -// GetTargetManifest godoc -// -// @Tags provider -// @Summary Get provider target manifest -// @Description Get provider target manifest -// @Param provider path string true "Provider name" -// @Success 200 -// @Success 200 {object} ProviderTargetManifest -// @Router /provider/{provider}/target-manifest [get] -// -// @id GetTargetManifest -func GetTargetManifest(ctx *gin.Context) { - providerName := ctx.Param("provider") - - server := server.GetInstance(nil) - - p, err := server.ProviderManager.GetProvider(providerName) - if err != nil { - ctx.AbortWithError(http.StatusNotFound, fmt.Errorf("provider not found: %w", err)) - return - } - - manifest, err := (*p).GetTargetManifest() - if err != nil { - ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to get provider manifest: %w", err)) - return - } - - ctx.JSON(200, manifest) -} diff --git a/pkg/api/controllers/runner/create.go b/pkg/api/controllers/runner/create.go new file mode 100644 index 0000000000..23276c6fe9 --- /dev/null +++ b/pkg/api/controllers/runner/create.go @@ -0,0 +1,46 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package runner + +import ( + "fmt" + "net/http" + + "github.com/daytonaio/daytona/pkg/server" + "github.com/daytonaio/daytona/pkg/services" + "github.com/gin-gonic/gin" +) + +// CreateRunner godoc +// +// @Tags runner +// @Summary Create a runner +// @Description Create a runner +// @Param runner body CreateRunnerDTO true "Runner" +// @Produce json +// @Success 200 {object} CreateRunnerResultDTO +// @Router /runner [post] +// +// @id CreateRunner +func CreateRunner(ctx *gin.Context) { + var createRunnerReq services.CreateRunnerDTO + err := ctx.BindJSON(&createRunnerReq) + if err != nil { + ctx.AbortWithError(http.StatusBadRequest, fmt.Errorf("invalid request body: %w", err)) + return + } + + server := server.GetInstance(nil) + + r, err := server.RunnerService.Create(ctx.Request.Context(), createRunnerReq) + if err != nil { + ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to create runner: %w", err)) + return + } + + ctx.JSON(200, services.CreateRunnerResultDTO{ + Runner: r.Runner, + ApiKey: r.ApiKey, + }) +} diff --git a/pkg/api/controllers/runner/delete.go b/pkg/api/controllers/runner/delete.go new file mode 100644 index 0000000000..ee01621aa3 --- /dev/null +++ b/pkg/api/controllers/runner/delete.go @@ -0,0 +1,36 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package runner + +import ( + "fmt" + "net/http" + + "github.com/daytonaio/daytona/pkg/server" + "github.com/gin-gonic/gin" +) + +// DeleteRunner godoc +// +// @Tags runner +// @Summary Delete runner +// @Description Delete runner +// @Param runnerId path string true "Runner ID" +// @Success 200 +// @Router /runner/{runnerId} [delete] +// +// @id DeleteRunner +func DeleteRunner(ctx *gin.Context) { + runnerId := ctx.Param("runnerId") + + server := server.GetInstance(nil) + + err := server.RunnerService.Delete(ctx.Request.Context(), runnerId) + if err != nil { + ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to delete runner: %w", err)) + return + } + + ctx.Status(200) +} diff --git a/pkg/api/controllers/runner/dto/dto.go b/pkg/api/controllers/runner/dto/dto.go new file mode 100644 index 0000000000..9590b77732 --- /dev/null +++ b/pkg/api/controllers/runner/dto/dto.go @@ -0,0 +1,14 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package dto + +import ( + "github.com/daytonaio/daytona/pkg/models" +) + +type UpdateRunnerMetadataDTO struct { + Uptime uint64 `json:"uptime" validate:"required" gorm:"not null"` + RunningJobs *uint64 `json:"runningJobs" validate:"optional" gorm:"not null"` + Providers []models.ProviderInfo `json:"providers" validate:"required" gorm:"serializer:json;not null"` +} // @name UpdateRunnerMetadataDTO diff --git a/pkg/api/controllers/runner/find.go b/pkg/api/controllers/runner/find.go new file mode 100644 index 0000000000..c35d19288c --- /dev/null +++ b/pkg/api/controllers/runner/find.go @@ -0,0 +1,42 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package runner + +import ( + "fmt" + "net/http" + + "github.com/daytonaio/daytona/pkg/server" + "github.com/daytonaio/daytona/pkg/stores" + "github.com/gin-gonic/gin" +) + +// FindRunner godoc +// +// @Tags runner +// @Summary Find a runner +// @Description Find a runner +// @Param runnerId path string true "Runner ID" +// @Produce json +// @Success 200 {object} RunnerDTO +// @Router /runner/{runnerId} [get] +// +// @id FindRunner +func FindRunner(ctx *gin.Context) { + runnerId := ctx.Param("runnerId") + + server := server.GetInstance(nil) + + r, err := server.RunnerService.Find(ctx.Request.Context(), runnerId) + if err != nil { + statusCode := http.StatusInternalServerError + if stores.IsRunnerNotFound(err) { + statusCode = http.StatusNotFound + } + ctx.AbortWithError(statusCode, fmt.Errorf("failed to get runner: %w", err)) + return + } + + ctx.JSON(200, r) +} diff --git a/pkg/api/controllers/runner/jobs.go b/pkg/api/controllers/runner/jobs.go new file mode 100644 index 0000000000..1484e46cf3 --- /dev/null +++ b/pkg/api/controllers/runner/jobs.go @@ -0,0 +1,111 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package runner + +import ( + "fmt" + "net/http" + "time" + + "github.com/daytonaio/daytona/pkg/server" + "github.com/daytonaio/daytona/pkg/services" + "github.com/daytonaio/daytona/pkg/stores" + "github.com/gin-gonic/gin" +) + +const LONG_POLL_TIMEOUT = 1 * time.Minute +const LONG_POLL_INTERVAL = 50 * time.Millisecond + +// ListRunnerJobs godoc +// +// @Tags runner +// @Summary List runner jobs +// @Description List runner jobs +// @Param runnerId path string true "Runner ID" +// @Produce json +// @Success 200 {array} Job +// @Router /runner/{runnerId}/jobs [get] +// +// @id ListRunnerJobs +func ListRunnerJobs(ctx *gin.Context) { + runnerId := ctx.Param("runnerId") + + server := server.GetInstance(nil) + + timeout := time.After(LONG_POLL_TIMEOUT) + ticker := time.NewTicker(LONG_POLL_INTERVAL) + defer ticker.Stop() + + for { + select { + case <-ctx.Request.Context().Done(): + // Handle client cancelling the request + ctx.AbortWithStatus(http.StatusRequestTimeout) + return + case <-timeout: + // Handle request timing out + ctx.JSON(http.StatusNoContent, nil) + return + case <-ticker.C: + // Check for new jobs + jobs, err := server.RunnerService.ListRunnerJobs(ctx.Request.Context(), runnerId) + if err != nil { + ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to get runner jobs: %w", err)) + return + } + if len(jobs) > 0 { + ctx.JSON(http.StatusOK, jobs) + return + } + } + } +} + +// UpdateJobState godoc +// +// @Tags runner +// @Summary Update job state +// @Description Update job state +// @Param runnerId path string true "Runner ID" +// @Param jobId path string true "Job ID" +// @Param updateJobState body UpdateJobState true "Update job state" +// @Produce json +// @Success 200 +// @Router /runner/{runnerId}/jobs/{jobId}/state [post] +// +// @id UpdateJobState +func UpdateJobState(ctx *gin.Context) { + runnerId := ctx.Param("runnerId") + jobId := ctx.Param("jobId") + + var updateJobState services.UpdateJobStateDTO + err := ctx.BindJSON(&updateJobState) + if err != nil { + ctx.AbortWithError(http.StatusBadRequest, fmt.Errorf("invalid request body: %w", err)) + return + } + + server := server.GetInstance(nil) + + job, err := server.JobService.Find(ctx.Request.Context(), &stores.JobFilter{ + Id: &jobId, + }) + if err != nil { + ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to get job: %w", err)) + return + } + + if job.RunnerId != nil && *job.RunnerId != runnerId { + ctx.AbortWithError(http.StatusUnauthorized, fmt.Errorf("job does not belong to runner")) + return + } + + err = server.RunnerService.UpdateJobState(ctx.Request.Context(), jobId, updateJobState) + if err != nil { + ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to update job state: %w", err)) + return + } + + ctx.Status(200) +} diff --git a/pkg/api/controllers/runner/list.go b/pkg/api/controllers/runner/list.go new file mode 100644 index 0000000000..4424a8523a --- /dev/null +++ b/pkg/api/controllers/runner/list.go @@ -0,0 +1,34 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package runner + +import ( + "fmt" + "net/http" + + "github.com/daytonaio/daytona/pkg/server" + "github.com/gin-gonic/gin" +) + +// ListRunners godoc +// +// @Tags runner +// @Summary List runners +// @Description List runners +// @Produce json +// @Success 200 {array} RunnerDTO +// @Router /runner [get] +// +// @id ListRunners +func ListRunners(ctx *gin.Context) { + server := server.GetInstance(nil) + + runners, err := server.RunnerService.List(ctx.Request.Context()) + if err != nil { + ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to register runner: %w", err)) + return + } + + ctx.JSON(200, runners) +} diff --git a/pkg/api/controllers/runner/metadata.go b/pkg/api/controllers/runner/metadata.go new file mode 100644 index 0000000000..da01b58eb3 --- /dev/null +++ b/pkg/api/controllers/runner/metadata.go @@ -0,0 +1,51 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package runner + +import ( + "fmt" + "net/http" + + "github.com/daytonaio/daytona/pkg/api/controllers/runner/dto" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/server" + "github.com/gin-gonic/gin" +) + +// UpdateRunnerMetadata godoc +// +// @Tags runner +// @Summary Update runner metadata +// @Description Update runner metadata +// @Param runnerId path string true "Runner ID" +// @Param runnerMetadata body UpdateRunnerMetadataDTO true "Runner Metadata" +// @Success 200 +// @Router /runner/{runnerId}/metadata [post] +// +// @id UpdateRunnerMetadata +func UpdateRunnerMetadata(ctx *gin.Context) { + runnerId := ctx.Param("runnerId") + + var runnerMetadata dto.UpdateRunnerMetadataDTO + err := ctx.BindJSON(&runnerMetadata) + if err != nil { + ctx.AbortWithError(http.StatusBadRequest, fmt.Errorf("invalid request body: %w", err)) + return + } + + server := server.GetInstance(nil) + + err = server.RunnerService.UpdateMetadata(ctx.Request.Context(), runnerId, &models.RunnerMetadata{ + RunnerId: runnerId, + Uptime: runnerMetadata.Uptime, + Providers: runnerMetadata.Providers, + RunningJobs: runnerMetadata.RunningJobs, + }) + if err != nil { + ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to set runner metadata for %s: %w", runnerId, err)) + return + } + + ctx.Status(200) +} diff --git a/pkg/api/controllers/provider/dto/dto.go b/pkg/api/controllers/runner/provider/dto/dto.go similarity index 100% rename from pkg/api/controllers/provider/dto/dto.go rename to pkg/api/controllers/runner/provider/dto/dto.go diff --git a/pkg/api/controllers/runner/provider/get.go b/pkg/api/controllers/runner/provider/get.go new file mode 100644 index 0000000000..ba5a05188d --- /dev/null +++ b/pkg/api/controllers/runner/provider/get.go @@ -0,0 +1,42 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package provider + +import ( + "fmt" + "net/http" + + "github.com/daytonaio/daytona/pkg/server" + "github.com/daytonaio/daytona/pkg/stores" + "github.com/gin-gonic/gin" +) + +// GetRunnerProviders godoc +// +// @Tags provider +// @Summary Get runner providers +// @Description Get runner providers +// @Param runnerId path string true "Runner ID" +// @Produce json +// @Success 200 {array} ProviderInfo +// @Router /runner/{runnerId}/provider [get] +// +// @id GetRunnerProviders +func GetRunnerProviders(ctx *gin.Context) { + runnerId := ctx.Param("runnerId") + + server := server.GetInstance(nil) + + r, err := server.RunnerService.Find(ctx.Request.Context(), runnerId) + if err != nil { + statusCode := http.StatusInternalServerError + if stores.IsRunnerNotFound(err) { + statusCode = http.StatusNotFound + } + ctx.AbortWithError(statusCode, fmt.Errorf("failed to get runner: %w", err)) + return + } + + ctx.JSON(200, r.Metadata.Providers) +} diff --git a/pkg/api/controllers/runner/provider/install.go b/pkg/api/controllers/runner/provider/install.go new file mode 100644 index 0000000000..e8d8a867f4 --- /dev/null +++ b/pkg/api/controllers/runner/provider/install.go @@ -0,0 +1,59 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package provider + +import ( + "fmt" + "net/http" + + "github.com/daytonaio/daytona/pkg/server" + "github.com/gin-gonic/gin" +) + +// InstallProvider godoc +// +// @Tags provider +// @Summary Install provider +// @Description Install provider +// @Param runnerId path string true "Runner ID" +// @Param providerName path string true "Provider name" +// @Param providerVersion query string false "Provider version - defaults to 'latest'" +// @Success 200 +// @Router /runner/{runnerId}/provider/{providerName}/install [post] +// +// @id InstallProvider +func InstallProvider(ctx *gin.Context) { + runnerId := ctx.Param("runnerId") + providerName := ctx.Param("providerName") + providerVersion := ctx.DefaultQuery("providerVersion", "latest") + + config, err := server.GetConfig() + if err != nil { + ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to get config: %w", err)) + return + } + + server := server.GetInstance(nil) + + installedProviders, err := server.RunnerService.ListProviders(ctx, &runnerId) + if err != nil { + ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to fetch installed providers: %w", err)) + return + } + + for _, provider := range installedProviders { + if provider.Name == providerName { + ctx.AbortWithError(http.StatusBadRequest, fmt.Errorf("provider %s is already installed", providerName)) + return + } + } + + err = server.RunnerService.InstallProvider(ctx.Request.Context(), runnerId, providerName, providerVersion, config.RegistryUrl) + if err != nil { + ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to install provider: %w", err)) + return + } + + ctx.Status(200) +} diff --git a/pkg/api/controllers/runner/provider/list.go b/pkg/api/controllers/runner/provider/list.go new file mode 100644 index 0000000000..2427a1e834 --- /dev/null +++ b/pkg/api/controllers/runner/provider/list.go @@ -0,0 +1,70 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package provider + +import ( + "fmt" + "net/http" + + _ "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/server" + "github.com/gin-gonic/gin" +) + +// ListProviders godoc +// +// @Tags provider +// @Summary List providers +// @Description List providers +// @Param runnerId query string false "Runner ID" +// @Produce json +// @Success 200 {array} models.ProviderInfo +// @Router /runner/provider [get] +// +// @id ListProviders +func ListProviders(ctx *gin.Context) { + runnerIdQuery := ctx.Query("runnerId") + + var runnerId *string + if runnerIdQuery != "" { + runnerId = &runnerIdQuery + } + + server := server.GetInstance(nil) + providers, err := server.RunnerService.ListProviders(ctx.Request.Context(), runnerId) + if err != nil { + ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to list providers: %w", err)) + return + } + + ctx.JSON(200, providers) +} + +// ListProvidersForInstall godoc +// +// @Tags provider +// @Summary List providers available for installation +// @Description List providers available for installation +// @Produce json +// @Success 200 {array} ProviderDTO +// @Router /runner/provider/for-install [get] +// +// @id ListProvidersForInstall +func ListProvidersForInstall(ctx *gin.Context) { + config, err := server.GetConfig() + if err != nil { + ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to get config: %w", err)) + return + } + + server := server.GetInstance(nil) + + providers, err := server.RunnerService.ListProvidersForInstall(ctx.Request.Context(), config.RegistryUrl) + if err != nil { + ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to list providers for install: %w", err)) + return + } + + ctx.JSON(200, providers) +} diff --git a/pkg/api/controllers/provider/uninstall.go b/pkg/api/controllers/runner/provider/uninstall.go similarity index 53% rename from pkg/api/controllers/provider/uninstall.go rename to pkg/api/controllers/runner/provider/uninstall.go index 08af2a8846..73929cfa23 100644 --- a/pkg/api/controllers/provider/uninstall.go +++ b/pkg/api/controllers/runner/provider/uninstall.go @@ -7,6 +7,7 @@ import ( "fmt" "net/http" + _ "github.com/daytonaio/daytona/pkg/models" "github.com/daytonaio/daytona/pkg/server" "github.com/gin-gonic/gin" ) @@ -14,20 +15,21 @@ import ( // UninstallProvider godoc // // @Tags provider -// @Summary Uninstall a provider -// @Description Uninstall a provider -// @Accept json -// @Param provider path string true "Provider to uninstall" +// @Summary Uninstall provider +// @Description Uninstall provider +// @Param runnerId path string true "Runner ID" +// @Param providerName path string true "Provider name" // @Success 200 -// @Router /provider/{provider}/uninstall [post] +// @Router /runner/{runnerId}/provider/{providerName}/uninstall [post] // // @id UninstallProvider func UninstallProvider(ctx *gin.Context) { - provider := ctx.Param("provider") + runnerId := ctx.Param("runnerId") + providerName := ctx.Param("providerName") server := server.GetInstance(nil) - err := server.ProviderManager.UninstallProvider(provider) + err := server.RunnerService.UninstallProvider(ctx.Request.Context(), runnerId, providerName) if err != nil { ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to uninstall provider: %w", err)) return diff --git a/pkg/api/controllers/runner/provider/update.go b/pkg/api/controllers/runner/provider/update.go new file mode 100644 index 0000000000..920745ff07 --- /dev/null +++ b/pkg/api/controllers/runner/provider/update.go @@ -0,0 +1,47 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package provider + +import ( + "fmt" + "net/http" + + _ "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/server" + "github.com/gin-gonic/gin" +) + +// UpdateProvider godoc +// +// @Tags provider +// @Summary Update provider +// @Description Update provider +// @Param runnerId path string true "Runner ID" +// @Param providerName path string true "Provider name" +// @Param providerVersion query string false "Provider version - defaults to 'latest'" +// @Success 200 +// @Router /runner/{runnerId}/provider/{providerName}/update [post] +// +// @id UpdateProvider +func UpdateProvider(ctx *gin.Context) { + runnerId := ctx.Param("runnerId") + providerName := ctx.Param("providerName") + providerVersion := ctx.DefaultQuery("providerVersion", "latest") + + config, err := server.GetConfig() + if err != nil { + ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to get config: %w", err)) + return + } + + server := server.GetInstance(nil) + + err = server.RunnerService.UpdateProvider(ctx.Request.Context(), runnerId, providerName, providerVersion, config.RegistryUrl) + if err != nil { + ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to update provider: %w", err)) + return + } + + ctx.Status(200) +} diff --git a/pkg/api/controllers/server/server.go b/pkg/api/controllers/server/server.go index 5e2602bf04..a81b894c5a 100644 --- a/pkg/api/controllers/server/server.go +++ b/pkg/api/controllers/server/server.go @@ -8,6 +8,7 @@ import ( "net/http" "github.com/daytonaio/daytona/pkg/server" + "github.com/daytonaio/daytona/pkg/server/headscale" "github.com/gin-gonic/gin" ) @@ -31,19 +32,19 @@ func GetConfig(ctx *gin.Context) { ctx.JSON(200, config) } -// SetConfig godoc +// SaveConfig godoc // // @Tags server -// @Summary Set the server configuration -// @Description Set the server configuration +// @Summary Save the server configuration +// @Description Save the server configuration // @Accept json // @Produce json // @Param config body ServerConfig true "Server configuration" // @Success 200 {object} ServerConfig -// @Router /server/config [post] +// @Router /server/config [put] // -// @id SetConfig -func SetConfig(ctx *gin.Context) { +// @id SaveConfig +func SaveConfig(ctx *gin.Context) { var c server.Config err := ctx.BindJSON(&c) if err != nil { @@ -60,20 +61,20 @@ func SetConfig(ctx *gin.Context) { ctx.JSON(200, c) } -// GenerateNetworkKey godoc +// CreateNetworkKey godoc // // @Tags server -// @Summary Generate a new authentication key -// @Description Generate a new authentication key +// @Summary Create a new authentication key +// @Description Create a new authentication key // @Produce json // @Success 200 {object} NetworkKey // @Router /server/network-key [post] // -// @id GenerateNetworkKey -func GenerateNetworkKey(ctx *gin.Context) { +// @id CreateNetworkKey +func CreateNetworkKey(ctx *gin.Context) { s := server.GetInstance(nil) - authKey, err := s.TailscaleServer.CreateAuthKey() + authKey, err := s.TailscaleServer.CreateAuthKey(headscale.HEADSCALE_USERNAME) if err != nil { ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to generate network key: %w", err)) return @@ -85,8 +86,8 @@ func GenerateNetworkKey(ctx *gin.Context) { // GetServerLogFiles godoc // // @Tags server -// @Summary List server log files -// @Description List server log files +// @Summary Get server log files +// @Description Get server log files // @Produce json // @Success 200 {array} string // @Router /server/logs [get] diff --git a/pkg/api/controllers/target/create.go b/pkg/api/controllers/target/create.go new file mode 100644 index 0000000000..bac18e54e5 --- /dev/null +++ b/pkg/api/controllers/target/create.go @@ -0,0 +1,68 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package target + +import ( + "fmt" + "net/http" + + "github.com/daytonaio/daytona/pkg/server" + "github.com/daytonaio/daytona/pkg/services" + "github.com/gin-gonic/gin" +) + +// CreateTarget godoc +// +// @Tags target +// @Summary Create a target +// @Description Create a target +// @Param target body CreateTargetDTO true "Create target" +// @Produce json +// @Success 200 {object} Target +// @Router /target [post] +// +// @id CreateTarget +func CreateTarget(ctx *gin.Context) { + var createTargetReq services.CreateTargetDTO + err := ctx.BindJSON(&createTargetReq) + if err != nil { + ctx.AbortWithError(http.StatusBadRequest, fmt.Errorf("invalid request body: %w", err)) + return + } + + server := server.GetInstance(nil) + + t, err := server.TargetService.Create(ctx.Request.Context(), createTargetReq) + if err != nil { + ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to create target: %w", err)) + return + } + + t.TargetConfig.Options = "" + ctx.JSON(200, t) +} + +// HandleSuccessfulCreation godoc +// +// @Tags target +// @Summary Handles successful creation of the target +// @Description Handles successful creation of the target +// @Param targetId path string true "Target ID or name" +// @Success 200 +// @Router /target/{targetId}/handle-successful-creation [post] +// +// @id HandleSuccessfulCreation +func HandleSuccessfulCreation(ctx *gin.Context) { + targetId := ctx.Param("targetId") + + server := server.GetInstance(nil) + + err := server.TargetService.HandleSuccessfulCreation(ctx.Request.Context(), targetId) + if err != nil { + ctx.AbortWithError(http.StatusNotFound, fmt.Errorf("failed to handle successful creation of target: %s", err.Error())) + return + } + + ctx.Status(200) +} diff --git a/pkg/api/controllers/target/delete.go b/pkg/api/controllers/target/delete.go new file mode 100644 index 0000000000..acc0911e7d --- /dev/null +++ b/pkg/api/controllers/target/delete.go @@ -0,0 +1,55 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package target + +import ( + "errors" + "fmt" + "net/http" + "strconv" + + "github.com/daytonaio/daytona/pkg/server" + "github.com/gin-gonic/gin" +) + +// DeleteTarget godoc +// +// @Tags target +// @Summary Delete target +// @Description Delete target +// @Param targetId path string true "Target ID" +// @Param force query bool false "Force" +// @Success 200 +// @Router /target/{targetId} [delete] +// +// @id DeleteTarget +func DeleteTarget(ctx *gin.Context) { + targetId := ctx.Param("targetId") + forceQuery := ctx.Query("force") + var err error + force := false + + if forceQuery != "" { + force, err = strconv.ParseBool(forceQuery) + if err != nil { + ctx.AbortWithError(http.StatusBadRequest, errors.New("invalid value for force flag")) + return + } + } + + server := server.GetInstance(nil) + + if force { + err = server.TargetService.ForceDelete(ctx.Request.Context(), targetId) + } else { + err = server.TargetService.Delete(ctx.Request.Context(), targetId) + } + + if err != nil { + ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to delete target: %w", err)) + return + } + + ctx.Status(200) +} diff --git a/pkg/api/controllers/target/dto/dto.go b/pkg/api/controllers/target/dto/dto.go new file mode 100644 index 0000000000..84527b3f18 --- /dev/null +++ b/pkg/api/controllers/target/dto/dto.go @@ -0,0 +1,12 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package dto + +type UpdateTargetMetadataDTO struct { + Uptime uint64 `json:"uptime" validate:"required"` +} // @name UpdateTargetMetadataDTO + +type UpdateTargetProviderMetadataDTO struct { + Metadata string `json:"metadata" validate:"required"` +} // @name UpdateTargetProviderMetadataDTO diff --git a/pkg/api/controllers/target/list.go b/pkg/api/controllers/target/list.go deleted file mode 100644 index 6a8a55726d..0000000000 --- a/pkg/api/controllers/target/list.go +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package target - -import ( - "encoding/json" - "fmt" - "net/http" - - "github.com/daytonaio/daytona/pkg/server" - "github.com/gin-gonic/gin" -) - -// ListTargets godoc -// -// @Tags target -// @Summary List targets -// @Description List targets -// @Produce json -// @Success 200 {array} ProviderTarget -// @Router /target [get] -// -// @id ListTargets -func ListTargets(ctx *gin.Context) { - server := server.GetInstance(nil) - - targets, err := server.ProviderTargetService.List(nil) - if err != nil { - ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to list targets: %w", err)) - return - } - - for _, target := range targets { - p, err := server.ProviderManager.GetProvider(target.ProviderInfo.Name) - if err != nil { - target.Options = fmt.Sprintf("Error: %s", err.Error()) - continue - } - - manifest, err := (*p).GetTargetManifest() - if err != nil { - target.Options = fmt.Sprintf("Error: %s", err.Error()) - continue - } - - var opts map[string]interface{} - err = json.Unmarshal([]byte(target.Options), &opts) - if err != nil { - target.Options = fmt.Sprintf("Error: %s", err.Error()) - continue - } - - for name, property := range *manifest { - if property.InputMasked { - delete(opts, name) - } - } - - updatedOptions, err := json.MarshalIndent(opts, "", " ") - if err != nil { - target.Options = fmt.Sprintf("Error: %s", err.Error()) - continue - } - - target.Options = string(updatedOptions) - } - - ctx.JSON(200, targets) -} diff --git a/pkg/api/controllers/target/metadata.go b/pkg/api/controllers/target/metadata.go new file mode 100644 index 0000000000..f2d00731c2 --- /dev/null +++ b/pkg/api/controllers/target/metadata.go @@ -0,0 +1,80 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package target + +import ( + "fmt" + "net/http" + + "github.com/daytonaio/daytona/pkg/api/controllers/target/dto" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/server" + "github.com/gin-gonic/gin" +) + +// UpdateTargetMetadata godoc +// +// @Tags target +// @Summary Update target metadata +// @Description Update target metadata +// @Param targetId path string true "Target ID" +// @Param targetMetadata body UpdateTargetMetadataDTO true "Target Metadata" +// @Success 200 +// @Router /target/{targetId}/metadata [post] +// +// @id UpdateTargetMetadata +func UpdateTargetMetadata(ctx *gin.Context) { + targetId := ctx.Param("targetId") + + var updateDTO dto.UpdateTargetMetadataDTO + err := ctx.BindJSON(&updateDTO) + if err != nil { + ctx.AbortWithError(http.StatusBadRequest, fmt.Errorf("invalid request body: %w", err)) + return + } + + server := server.GetInstance(nil) + + _, err = server.TargetService.UpdateMetadata(ctx.Request.Context(), targetId, &models.TargetMetadata{ + Uptime: updateDTO.Uptime, + }) + if err != nil { + ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to set target metadata for %s: %w", targetId, err)) + return + } + + ctx.Status(200) +} + +// UpdateTargetProviderMetadata godoc +// +// @Tags target +// @Summary Update target provider metadata +// @Description Update target provider metadata +// @Param targetId path string true "Target ID" +// @Param metadata body UpdateTargetProviderMetadataDTO true "Provider metadata" +// @Success 200 +// @Router /target/{targetId}/provider-metadata [post] +// +// @id UpdateTargetProviderMetadata +func UpdateTargetProviderMetadata(ctx *gin.Context) { + targetId := ctx.Param("targetId") + + var metadata dto.UpdateTargetProviderMetadataDTO + err := ctx.BindJSON(&metadata) + if err != nil { + ctx.AbortWithError(http.StatusBadRequest, fmt.Errorf("invalid request body: %w", err)) + return + } + + server := server.GetInstance(nil) + + err = server.TargetService.UpdateProviderMetadata(ctx.Request.Context(), targetId, metadata.Metadata) + if err != nil { + ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to update target provider metadata for %s: %w", targetId, err)) + return + } + + ctx.Status(200) +} diff --git a/pkg/api/controllers/target/remove.go b/pkg/api/controllers/target/remove.go deleted file mode 100644 index dcf61ea6ce..0000000000 --- a/pkg/api/controllers/target/remove.go +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package target - -import ( - "fmt" - "net/http" - - "github.com/daytonaio/daytona/pkg/provider" - "github.com/daytonaio/daytona/pkg/server" - "github.com/gin-gonic/gin" -) - -// RemoveTarget godoc -// -// @Tags target -// @Summary Remove a target -// @Description Remove a target -// @Param target path string true "Target name" -// @Success 204 -// @Router /target/{target} [delete] -// -// @id RemoveTarget -func RemoveTarget(ctx *gin.Context) { - targetName := ctx.Param("target") - - server := server.GetInstance(nil) - - target, err := server.ProviderTargetService.Find(&provider.TargetFilter{ - Name: &targetName, - }) - if err != nil { - ctx.AbortWithError(http.StatusNotFound, fmt.Errorf("failed to find target: %w", err)) - return - } - - err = server.ProviderTargetService.Delete(target) - if err != nil { - ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to remove target: %w", err)) - return - } - - ctx.Status(204) -} diff --git a/pkg/api/controllers/target/restart.go b/pkg/api/controllers/target/restart.go new file mode 100644 index 0000000000..d690cec38e --- /dev/null +++ b/pkg/api/controllers/target/restart.go @@ -0,0 +1,36 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package target + +import ( + "fmt" + "net/http" + + "github.com/daytonaio/daytona/pkg/server" + "github.com/gin-gonic/gin" +) + +// RestartTarget godoc +// +// @Tags target +// @Summary Restart target +// @Description Restart target +// @Param targetId path string true "Target ID or Name" +// @Success 200 +// @Router /target/{targetId}/restart [post] +// +// @id RestartTarget +func RestartTarget(ctx *gin.Context) { + targetId := ctx.Param("targetId") + + server := server.GetInstance(nil) + + err := server.TargetService.Restart(ctx.Request.Context(), targetId) + if err != nil { + ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to restart target %s: %w", targetId, err)) + return + } + + ctx.Status(200) +} diff --git a/pkg/api/controllers/target/set.go b/pkg/api/controllers/target/set.go deleted file mode 100644 index 93b681f23e..0000000000 --- a/pkg/api/controllers/target/set.go +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package target - -import ( - "fmt" - "net/http" - - "github.com/daytonaio/daytona/internal/util/apiclient/conversion" - "github.com/daytonaio/daytona/pkg/provider" - "github.com/daytonaio/daytona/pkg/server" - "github.com/daytonaio/daytona/pkg/server/providertargets/dto" - "github.com/gin-gonic/gin" -) - -// SetTarget godoc -// -// @Tags target -// @Summary Set a target -// @Description Set a target -// @Param target body CreateProviderTargetDTO true "Target to set" -// @Success 201 -// @Router /target [put] -// -// @id SetTarget -func SetTarget(ctx *gin.Context) { - var req dto.CreateProviderTargetDTO - err := ctx.BindJSON(&req) - if err != nil { - ctx.AbortWithError(http.StatusBadRequest, fmt.Errorf("invalid request body: %w", err)) - return - } - - server := server.GetInstance(nil) - - target := conversion.ToProviderTarget(req) - - err = server.ProviderTargetService.Save(target) - if err != nil { - ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to set target: %w", err)) - return - } - - ctx.Status(201) -} - -// SetDefaultTarget godoc -// -// @Tags target -// @Summary Set target to default -// @Description Set target to default -// @Param target path string true "Target name" -// @Success 200 -// @Router /target/{target}/set-default [patch] -// -// @id SetDefaultTarget -func SetDefaultTarget(ctx *gin.Context) { - targetName := ctx.Param("target") - - server := server.GetInstance(nil) - - target, err := server.ProviderTargetService.Find(&provider.TargetFilter{ - Name: &targetName, - }) - if err != nil { - ctx.AbortWithError(http.StatusNotFound, fmt.Errorf("failed to find target: %w", err)) - return - } - - err = server.ProviderTargetService.SetDefault(target) - if err != nil { - ctx.AbortWithError(http.StatusNotFound, fmt.Errorf("failed to set project config to default: %s", err.Error())) - return - } - - ctx.Status(200) -} diff --git a/pkg/api/controllers/target/set_default.go b/pkg/api/controllers/target/set_default.go new file mode 100644 index 0000000000..7c2a476119 --- /dev/null +++ b/pkg/api/controllers/target/set_default.go @@ -0,0 +1,36 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package target + +import ( + "fmt" + "net/http" + + "github.com/daytonaio/daytona/pkg/server" + "github.com/gin-gonic/gin" +) + +// SetDefaultTarget godoc +// +// @Tags target +// @Summary Set target to be used by default +// @Description Set target to be used by default +// @Param targetId path string true "Target ID or name" +// @Success 200 +// @Router /target/{targetId}/set-default [patch] +// +// @id SetDefaultTarget +func SetDefaultTarget(ctx *gin.Context) { + targetId := ctx.Param("targetId") + + server := server.GetInstance(nil) + + err := server.TargetService.SetDefault(ctx.Request.Context(), targetId) + if err != nil { + ctx.AbortWithError(http.StatusNotFound, fmt.Errorf("failed to set target to default: %s", err.Error())) + return + } + + ctx.Status(200) +} diff --git a/pkg/api/controllers/target/start.go b/pkg/api/controllers/target/start.go new file mode 100644 index 0000000000..3046961ba7 --- /dev/null +++ b/pkg/api/controllers/target/start.go @@ -0,0 +1,36 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package target + +import ( + "fmt" + "net/http" + + "github.com/daytonaio/daytona/pkg/server" + "github.com/gin-gonic/gin" +) + +// StartTarget godoc +// +// @Tags target +// @Summary Start target +// @Description Start target +// @Param targetId path string true "Target ID or Name" +// @Success 200 +// @Router /target/{targetId}/start [post] +// +// @id StartTarget +func StartTarget(ctx *gin.Context) { + targetId := ctx.Param("targetId") + + server := server.GetInstance(nil) + + err := server.TargetService.Start(ctx.Request.Context(), targetId) + if err != nil { + ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to start target %s: %w", targetId, err)) + return + } + + ctx.Status(200) +} diff --git a/pkg/api/controllers/target/stop.go b/pkg/api/controllers/target/stop.go new file mode 100644 index 0000000000..68595e9498 --- /dev/null +++ b/pkg/api/controllers/target/stop.go @@ -0,0 +1,36 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package target + +import ( + "fmt" + "net/http" + + "github.com/daytonaio/daytona/pkg/server" + "github.com/gin-gonic/gin" +) + +// StopTarget godoc +// +// @Tags target +// @Summary Stop target +// @Description Stop target +// @Param targetId path string true "Target ID or Name" +// @Success 200 +// @Router /target/{targetId}/stop [post] +// +// @id StopTarget +func StopTarget(ctx *gin.Context) { + targetId := ctx.Param("targetId") + + server := server.GetInstance(nil) + + err := server.TargetService.Stop(ctx.Request.Context(), targetId) + if err != nil { + ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to stop target %s: %w", targetId, err)) + return + } + + ctx.Status(200) +} diff --git a/pkg/api/controllers/target/target.go b/pkg/api/controllers/target/target.go new file mode 100644 index 0000000000..f6cfe02421 --- /dev/null +++ b/pkg/api/controllers/target/target.go @@ -0,0 +1,140 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package target + +import ( + "fmt" + "net/http" + + "github.com/daytonaio/daytona/pkg/api/util" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/server" + "github.com/daytonaio/daytona/pkg/services" + "github.com/daytonaio/daytona/pkg/stores" + "github.com/gin-gonic/gin" +) + +// FindTarget godoc +// +// @Tags target +// @Summary Find target +// @Description Find target +// @Produce json +// @Param targetId path string true "Target ID or Name" +// @Param showOptions query bool false "Show target config options" +// @Success 200 {object} TargetDTO +// @Router /target/{targetId} [get] +// +// @id FindTarget +func FindTarget(ctx *gin.Context) { + targetId := ctx.Param("targetId") + showTargetConfigOptionsQuery := ctx.Query("showOptions") + var showTargetConfigOptions bool + if showTargetConfigOptionsQuery == "true" { + showTargetConfigOptions = true + } + + server := server.GetInstance(nil) + + t, err := server.TargetService.Find(ctx.Request.Context(), &stores.TargetFilter{IdOrName: &targetId}, services.TargetRetrievalParams{}) + if err != nil { + statusCode := http.StatusInternalServerError + if stores.IsTargetNotFound(err) || services.IsTargetDeleted(err) { + statusCode = http.StatusNotFound + } + ctx.AbortWithError(statusCode, fmt.Errorf("failed to find target: %w", err)) + return + } + + if !showTargetConfigOptions { + t.TargetConfig.Options = "" + } + + apiKeyType, ok := ctx.Get("apiKeyType") + if !ok || apiKeyType == models.ApiKeyTypeClient { + for i := range t.Workspaces { + util.HideDaytonaEnvVars(&t.Workspaces[i].EnvVars) + t.Workspaces[i].ApiKey = "" + } + + util.HideDaytonaEnvVars(&t.EnvVars) + t.ApiKey = "" + } + + ctx.JSON(200, t) +} + +// GetTargetState godoc +// +// @Tags target +// @Summary Get target state +// @Description Get target state +// @Produce json +// @Param targetId path string true "Target ID or Name" +// @Success 200 {object} ResourceState +// @Router /target/{targetId}/state [get] +// +// @id GetTargetState +func GetTargetState(ctx *gin.Context) { + targetId := ctx.Param("targetId") + + server := server.GetInstance(nil) + + t, err := server.TargetService.Find(ctx.Request.Context(), &stores.TargetFilter{IdOrName: &targetId}, services.TargetRetrievalParams{}) + if err != nil { + statusCode := http.StatusInternalServerError + if stores.IsTargetNotFound(err) || services.IsTargetDeleted(err) { + statusCode = http.StatusNotFound + } + ctx.AbortWithError(statusCode, fmt.Errorf("failed to find target: %w", err)) + return + } + + ctx.JSON(200, t.State) +} + +// ListTargets godoc +// +// @Tags target +// @Summary List targets +// @Description List targets +// @Param showOptions query bool false "Show target config options" +// @Produce json +// @Success 200 {array} TargetDTO +// @Router /target [get] +// +// @id ListTargets +func ListTargets(ctx *gin.Context) { + server := server.GetInstance(nil) + showTargetConfigOptionsQuery := ctx.Query("showOptions") + var showTargetConfigOptions bool + if showTargetConfigOptionsQuery == "true" { + showTargetConfigOptions = true + } + + targetList, err := server.TargetService.List(ctx.Request.Context(), nil, services.TargetRetrievalParams{}) + if err != nil { + ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to list targets: %w", err)) + return + } + + for i := range targetList { + if !showTargetConfigOptions { + targetList[i].TargetConfig.Options = "" + } + + apiKeyType, ok := ctx.Get("apiKeyType") + if !ok || apiKeyType == models.ApiKeyTypeClient { + for j := range targetList[i].Workspaces { + util.HideDaytonaEnvVars(&targetList[i].Workspaces[j].EnvVars) + targetList[i].Workspaces[j].ApiKey = "" + } + + util.HideDaytonaEnvVars(&targetList[i].EnvVars) + targetList[i].ApiKey = "" + } + } + + ctx.JSON(200, targetList) +} diff --git a/pkg/api/controllers/targetconfig/create.go b/pkg/api/controllers/targetconfig/create.go new file mode 100644 index 0000000000..850572afb9 --- /dev/null +++ b/pkg/api/controllers/targetconfig/create.go @@ -0,0 +1,53 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package targetconfig + +import ( + "fmt" + "net/http" + + "github.com/daytonaio/daytona/pkg/server" + "github.com/daytonaio/daytona/pkg/services" + "github.com/gin-gonic/gin" +) + +// CreateTargetConfig godoc +// +// @Tags target-config +// @Summary Create a target config +// @Description Create a target config +// @Param targetConfig body CreateTargetConfigDTO true "Target config to create" +// @Param showOptions query bool false "Show target config options" +// @Success 200 {object} TargetConfig +// @Router /target-config [post] +// +// @id CreateTargetConfig +func CreateTargetConfig(ctx *gin.Context) { + showTargetConfigOptionsQuery := ctx.Query("showOptions") + var showTargetConfigOptions bool + if showTargetConfigOptionsQuery == "true" { + showTargetConfigOptions = true + } + + var req services.CreateTargetConfigDTO + err := ctx.BindJSON(&req) + if err != nil { + ctx.AbortWithError(http.StatusBadRequest, fmt.Errorf("invalid request body: %w", err)) + return + } + + server := server.GetInstance(nil) + + targetConfig, err := server.TargetConfigService.Create(ctx.Request.Context(), req) + if err != nil { + ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to set target config: %w", err)) + return + } + + if !showTargetConfigOptions { + targetConfig.Options = "" + } + + ctx.JSON(200, targetConfig) +} diff --git a/pkg/api/controllers/targetconfig/delete.go b/pkg/api/controllers/targetconfig/delete.go new file mode 100644 index 0000000000..ad2efee045 --- /dev/null +++ b/pkg/api/controllers/targetconfig/delete.go @@ -0,0 +1,36 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package targetconfig + +import ( + "fmt" + "net/http" + + "github.com/daytonaio/daytona/pkg/server" + "github.com/gin-gonic/gin" +) + +// DeleteTargetConfig godoc +// +// @Tags target-config +// @Summary Delete a target config +// @Description Delete a target config +// @Param configId path string true "Target Config Id" +// @Success 204 +// @Router /target-config/{configId} [delete] +// +// @id DeleteTargetConfig +func DeleteTargetConfig(ctx *gin.Context) { + configId := ctx.Param("configId") + + server := server.GetInstance(nil) + + err := server.TargetConfigService.Delete(ctx.Request.Context(), configId) + if err != nil { + ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to delete target config: %w", err)) + return + } + + ctx.Status(204) +} diff --git a/pkg/api/controllers/targetconfig/list.go b/pkg/api/controllers/targetconfig/list.go new file mode 100644 index 0000000000..ac2be887ed --- /dev/null +++ b/pkg/api/controllers/targetconfig/list.go @@ -0,0 +1,46 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package targetconfig + +import ( + "fmt" + "net/http" + + "github.com/daytonaio/daytona/pkg/server" + "github.com/gin-gonic/gin" +) + +// ListTargetConfigs godoc +// +// @Tags target-config +// @Summary List target configs +// @Description List target configs +// @Param showOptions query bool false "Show target config options" +// @Produce json +// @Success 200 {array} TargetConfig +// @Router /target-config [get] +// +// @id ListTargetConfigs +func ListTargetConfigs(ctx *gin.Context) { + server := server.GetInstance(nil) + showTargetConfigOptionsQuery := ctx.Query("showOptions") + var showTargetConfigOptions bool + if showTargetConfigOptionsQuery == "true" { + showTargetConfigOptions = true + } + + targetConfigs, err := server.TargetConfigService.List(ctx.Request.Context()) + if err != nil { + ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to list target configs: %w", err)) + return + } + + if !showTargetConfigOptions { + for _, targetConfig := range targetConfigs { + targetConfig.Options = "" + } + } + + ctx.JSON(200, targetConfigs) +} diff --git a/pkg/api/controllers/workspace/create.go b/pkg/api/controllers/workspace/create.go index 58cd980dba..2bed9a1205 100644 --- a/pkg/api/controllers/workspace/create.go +++ b/pkg/api/controllers/workspace/create.go @@ -7,9 +7,10 @@ import ( "fmt" "net/http" + "github.com/daytonaio/daytona/pkg/api/util" + "github.com/daytonaio/daytona/pkg/models" "github.com/daytonaio/daytona/pkg/server" - "github.com/daytonaio/daytona/pkg/server/workspaces" - "github.com/daytonaio/daytona/pkg/server/workspaces/dto" + "github.com/daytonaio/daytona/pkg/services" "github.com/gin-gonic/gin" ) @@ -20,12 +21,12 @@ import ( // @Description Create a workspace // @Param workspace body CreateWorkspaceDTO true "Create workspace" // @Produce json -// @Success 200 {object} Workspace +// @Success 200 {object} WorkspaceDTO // @Router /workspace [post] // // @id CreateWorkspace func CreateWorkspace(ctx *gin.Context) { - var createWorkspaceReq dto.CreateWorkspaceDTO + var createWorkspaceReq services.CreateWorkspaceDTO err := ctx.BindJSON(&createWorkspaceReq) if err != nil { ctx.AbortWithError(http.StatusBadRequest, fmt.Errorf("invalid request body: %w", err)) @@ -34,15 +35,19 @@ func CreateWorkspace(ctx *gin.Context) { server := server.GetInstance(nil) - w, err := server.WorkspaceService.CreateWorkspace(ctx.Request.Context(), createWorkspaceReq) + w, err := server.WorkspaceService.Create(ctx.Request.Context(), createWorkspaceReq) if err != nil { - if workspaces.IsWorkspaceAlreadyExists(err) { - ctx.AbortWithError(http.StatusConflict, fmt.Errorf("workspace already exists: %w", err)) - return - } ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to create workspace: %w", err)) return } + apiKeyType, ok := ctx.Get("apiKeyType") + if !ok || apiKeyType == models.ApiKeyTypeClient { + util.HideDaytonaEnvVars(&w.EnvVars) + util.HideDaytonaEnvVars(&w.Target.EnvVars) + w.ApiKey = "" + w.Target.ApiKey = "" + } + ctx.JSON(200, w) } diff --git a/pkg/api/controllers/workspace/delete.go b/pkg/api/controllers/workspace/delete.go new file mode 100644 index 0000000000..0b5feb1cee --- /dev/null +++ b/pkg/api/controllers/workspace/delete.go @@ -0,0 +1,55 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package workspace + +import ( + "errors" + "fmt" + "net/http" + "strconv" + + "github.com/daytonaio/daytona/pkg/server" + "github.com/gin-gonic/gin" +) + +// DeleteWorkspace godoc +// +// @Tags workspace +// @Summary Delete workspace +// @Description Delete workspace +// @Param workspaceId path string true "Workspace ID" +// @Param force query bool false "Force" +// @Success 200 +// @Router /workspace/{workspaceId} [delete] +// +// @id DeleteWorkspace +func DeleteWorkspace(ctx *gin.Context) { + workspaceId := ctx.Param("workspaceId") + forceQuery := ctx.Query("force") + var err error + force := false + + if forceQuery != "" { + force, err = strconv.ParseBool(forceQuery) + if err != nil { + ctx.AbortWithError(http.StatusBadRequest, errors.New("invalid value for force flag")) + return + } + } + + server := server.GetInstance(nil) + + if force { + err = server.WorkspaceService.ForceDelete(ctx.Request.Context(), workspaceId) + } else { + err = server.WorkspaceService.Delete(ctx.Request.Context(), workspaceId) + } + + if err != nil { + ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to delete workspace: %w", err)) + return + } + + ctx.Status(200) +} diff --git a/pkg/api/controllers/workspace/dto/dto.go b/pkg/api/controllers/workspace/dto/dto.go index ae4501c0b4..de4672f098 100644 --- a/pkg/api/controllers/workspace/dto/dto.go +++ b/pkg/api/controllers/workspace/dto/dto.go @@ -4,10 +4,14 @@ package dto import ( - "github.com/daytonaio/daytona/pkg/workspace/project" + "github.com/daytonaio/daytona/pkg/models" ) -type SetProjectState struct { - Uptime uint64 `json:"uptime" validate:"required"` - GitStatus *project.GitStatus `json:"gitStatus,omitempty" validate:"optional"` -} // @name SetProjectState +type UpdateWorkspaceMetadataDTO struct { + Uptime uint64 `json:"uptime" validate:"required"` + GitStatus *models.GitStatus `json:"gitStatus,omitempty" validate:"optional"` +} // @name UpdateWorkspaceMetadataDTO + +type UpdateWorkspaceProviderMetadataDTO struct { + Metadata string `json:"metadata" validate:"required"` +} // @name UpdateWorkspaceProviderMetadataDTO diff --git a/pkg/api/controllers/workspace/labels.go b/pkg/api/controllers/workspace/labels.go new file mode 100644 index 0000000000..5c938ab6fc --- /dev/null +++ b/pkg/api/controllers/workspace/labels.go @@ -0,0 +1,54 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package workspace + +import ( + "fmt" + "net/http" + + "github.com/daytonaio/daytona/pkg/api/util" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/server" + "github.com/gin-gonic/gin" +) + +// UpdateWorkspaceLabels godoc +// +// @Tags workspace +// @Summary Update workspace labels +// @Description Update workspace labels +// @Param workspaceId path string true "Workspace ID or Name" +// @Param labels body map[string]string true "Labels" +// @Success 200 {object} WorkspaceDTO +// @Router /workspace/{workspaceId}/labels [post] +// +// @id UpdateWorkspaceLabels +func UpdateWorkspaceLabels(ctx *gin.Context) { + workspaceId := ctx.Param("workspaceId") + + var req map[string]string + err := ctx.BindJSON(&req) + if err != nil { + ctx.AbortWithError(http.StatusBadRequest, fmt.Errorf("invalid request body: %s", err.Error())) + return + } + + server := server.GetInstance(nil) + + w, err := server.WorkspaceService.UpdateLabels(ctx.Request.Context(), workspaceId, req) + if err != nil { + ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to update labels for workspace %s: %w", workspaceId, err)) + return + } + + apiKeyType, ok := ctx.Get("apiKeyType") + if !ok || apiKeyType == models.ApiKeyTypeClient { + util.HideDaytonaEnvVars(&w.EnvVars) + util.HideDaytonaEnvVars(&w.Target.EnvVars) + w.ApiKey = "" + w.Target.ApiKey = "" + } + + ctx.JSON(200, w) +} diff --git a/pkg/api/controllers/workspace/metadata.go b/pkg/api/controllers/workspace/metadata.go new file mode 100644 index 0000000000..8f7c5e3d30 --- /dev/null +++ b/pkg/api/controllers/workspace/metadata.go @@ -0,0 +1,81 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package workspace + +import ( + "fmt" + "net/http" + + "github.com/daytonaio/daytona/pkg/api/controllers/workspace/dto" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/server" + "github.com/gin-gonic/gin" +) + +// UpdateWorkspaceMetadata godoc +// +// @Tags workspace +// @Summary Update workspace metadata +// @Description Update workspace metadata +// @Param workspaceId path string true "Workspace ID" +// @Param workspaceMetadata body UpdateWorkspaceMetadataDTO true "Workspace Metadata" +// @Success 200 +// @Router /workspace/{workspaceId}/metadata [post] +// +// @id UpdateWorkspaceMetadata +func UpdateWorkspaceMetadata(ctx *gin.Context) { + workspaceId := ctx.Param("workspaceId") + + var updateDTO dto.UpdateWorkspaceMetadataDTO + err := ctx.BindJSON(&updateDTO) + if err != nil { + ctx.AbortWithError(http.StatusBadRequest, fmt.Errorf("invalid request body: %w", err)) + return + } + + server := server.GetInstance(nil) + + _, err = server.WorkspaceService.UpdateMetadata(ctx.Request.Context(), workspaceId, &models.WorkspaceMetadata{ + Uptime: updateDTO.Uptime, + GitStatus: updateDTO.GitStatus, + }) + if err != nil { + ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to set workspace metadata for %s: %w", workspaceId, err)) + return + } + + ctx.Status(200) +} + +// UpdateWorkspaceProviderMetadata godoc +// +// @Tags workspace +// @Summary Update workspace provider metadata +// @Description Update workspace provider metadata +// @Param workspaceId path string true "Workspace ID" +// @Param metadata body UpdateWorkspaceProviderMetadataDTO true "Provider metadata" +// @Success 200 +// @Router /workspace/{workspaceId}/provider-metadata [post] +// +// @id UpdateWorkspaceProviderMetadata +func UpdateWorkspaceProviderMetadata(ctx *gin.Context) { + workspaceId := ctx.Param("workspaceId") + + var metadata dto.UpdateWorkspaceProviderMetadataDTO + err := ctx.BindJSON(&metadata) + if err != nil { + ctx.AbortWithError(http.StatusBadRequest, fmt.Errorf("invalid request body: %w", err)) + return + } + + server := server.GetInstance(nil) + + err = server.WorkspaceService.UpdateProviderMetadata(ctx.Request.Context(), workspaceId, metadata.Metadata) + if err != nil { + ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to update workspace provider metadata for %s: %w", workspaceId, err)) + return + } + + ctx.Status(200) +} diff --git a/pkg/api/controllers/workspace/project.go b/pkg/api/controllers/workspace/project.go deleted file mode 100644 index 1a1ee34209..0000000000 --- a/pkg/api/controllers/workspace/project.go +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package workspace - -import ( - "fmt" - "net/http" - "time" - - "github.com/daytonaio/daytona/pkg/api/controllers/workspace/dto" - "github.com/daytonaio/daytona/pkg/server" - "github.com/daytonaio/daytona/pkg/workspace/project" - "github.com/gin-gonic/gin" -) - -// SetProjectState godoc -// -// @Tags workspace -// @Summary Set project state -// @Description Set project state -// @Param workspaceId path string true "Workspace ID or Name" -// @Param projectId path string true "Project ID" -// @Param setState body SetProjectState true "Set State" -// @Success 200 -// @Router /workspace/{workspaceId}/{projectId}/state [post] -// -// @id SetProjectState -func SetProjectState(ctx *gin.Context) { - workspaceId := ctx.Param("workspaceId") - projectId := ctx.Param("projectId") - - var setProjectStateDTO dto.SetProjectState - err := ctx.BindJSON(&setProjectStateDTO) - if err != nil { - ctx.AbortWithError(http.StatusBadRequest, fmt.Errorf("invalid request body: %w", err)) - return - } - - server := server.GetInstance(nil) - - _, err = server.WorkspaceService.SetProjectState(workspaceId, projectId, &project.ProjectState{ - Uptime: setProjectStateDTO.Uptime, - UpdatedAt: time.Now().Format(time.RFC1123), - GitStatus: setProjectStateDTO.GitStatus, - }) - if err != nil { - ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to stop workspace %s: %w", workspaceId, err)) - return - } - - ctx.Status(200) -} diff --git a/pkg/api/controllers/workspace/restart.go b/pkg/api/controllers/workspace/restart.go new file mode 100644 index 0000000000..978bc1671a --- /dev/null +++ b/pkg/api/controllers/workspace/restart.go @@ -0,0 +1,36 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package workspace + +import ( + "fmt" + "net/http" + + "github.com/daytonaio/daytona/pkg/server" + "github.com/gin-gonic/gin" +) + +// RestartWorkspace godoc +// +// @Tags workspace +// @Summary Restart workspace +// @Description Restart workspace +// @Param workspaceId path string true "Workspace ID or Name" +// @Success 200 +// @Router /workspace/{workspaceId}/restart [post] +// +// @id RestartWorkspace +func RestartWorkspace(ctx *gin.Context) { + workspaceId := ctx.Param("workspaceId") + + server := server.GetInstance(nil) + + err := server.WorkspaceService.Restart(ctx.Request.Context(), workspaceId) + if err != nil { + ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to restart workspace %s: %w", workspaceId, err)) + return + } + + ctx.Status(200) +} diff --git a/pkg/api/controllers/workspace/start.go b/pkg/api/controllers/workspace/start.go index e34d6c54ce..b6799adfb4 100644 --- a/pkg/api/controllers/workspace/start.go +++ b/pkg/api/controllers/workspace/start.go @@ -26,7 +26,7 @@ func StartWorkspace(ctx *gin.Context) { server := server.GetInstance(nil) - err := server.WorkspaceService.StartWorkspace(ctx.Request.Context(), workspaceId) + err := server.WorkspaceService.Start(ctx.Request.Context(), workspaceId) if err != nil { ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to start workspace %s: %w", workspaceId, err)) return @@ -34,29 +34,3 @@ func StartWorkspace(ctx *gin.Context) { ctx.Status(200) } - -// StartProject godoc -// -// @Tags workspace -// @Summary Start project -// @Description Start project -// @Param workspaceId path string true "Workspace ID or Name" -// @Param projectId path string true "Project ID" -// @Success 200 -// @Router /workspace/{workspaceId}/{projectId}/start [post] -// -// @id StartProject -func StartProject(ctx *gin.Context) { - workspaceId := ctx.Param("workspaceId") - projectId := ctx.Param("projectId") - - server := server.GetInstance(nil) - - err := server.WorkspaceService.StartProject(ctx.Request.Context(), workspaceId, projectId) - if err != nil { - ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to start project %s: %w", projectId, err)) - return - } - - ctx.Status(200) -} diff --git a/pkg/api/controllers/workspace/stop.go b/pkg/api/controllers/workspace/stop.go index f738fd496e..c1363a2d56 100644 --- a/pkg/api/controllers/workspace/stop.go +++ b/pkg/api/controllers/workspace/stop.go @@ -26,7 +26,7 @@ func StopWorkspace(ctx *gin.Context) { server := server.GetInstance(nil) - err := server.WorkspaceService.StopWorkspace(ctx.Request.Context(), workspaceId) + err := server.WorkspaceService.Stop(ctx.Request.Context(), workspaceId) if err != nil { ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to stop workspace %s: %w", workspaceId, err)) return @@ -34,29 +34,3 @@ func StopWorkspace(ctx *gin.Context) { ctx.Status(200) } - -// StopProject godoc -// -// @Tags workspace -// @Summary Stop project -// @Description Stop project -// @Param workspaceId path string true "Workspace ID or Name" -// @Param projectId path string true "Project ID" -// @Success 200 -// @Router /workspace/{workspaceId}/{projectId}/stop [post] -// -// @id StopProject -func StopProject(ctx *gin.Context) { - workspaceId := ctx.Param("workspaceId") - projectId := ctx.Param("projectId") - - server := server.GetInstance(nil) - - err := server.WorkspaceService.StopProject(ctx.Request.Context(), workspaceId, projectId) - if err != nil { - ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to stop project %s: %w", projectId, err)) - return - } - - ctx.Status(200) -} diff --git a/pkg/api/controllers/workspace/toolbox/fs.go b/pkg/api/controllers/workspace/toolbox/fs.go index 35854ecd6e..7c61e91e93 100644 --- a/pkg/api/controllers/workspace/toolbox/fs.go +++ b/pkg/api/controllers/workspace/toolbox/fs.go @@ -9,14 +9,13 @@ import "github.com/gin-gonic/gin" // // @Tags workspace toolbox // @Summary Create folder -// @Description Create folder inside workspace project +// @Description Create folder inside a workspace // @Produce json // @Param workspaceId path string true "Workspace ID or Name" -// @Param projectId path string true "Project ID" // @Param path query string true "Path" // @Param mode query string true "Mode" // @Success 201 -// @Router /workspace/{workspaceId}/{projectId}/toolbox/files/folder [post] +// @Router /workspace/{workspaceId}/toolbox/files/folder [post] // // @id FsCreateFolder func FsCreateFolder(ctx *gin.Context) { @@ -27,13 +26,12 @@ func FsCreateFolder(ctx *gin.Context) { // // @Tags workspace toolbox // @Summary Delete file -// @Description Delete file inside workspace project +// @Description Delete file inside a workspace // @Produce json // @Param workspaceId path string true "Workspace ID or Name" -// @Param projectId path string true "Project ID" // @Param path query string true "Path" // @Success 204 -// @Router /workspace/{workspaceId}/{projectId}/toolbox/files [delete] +// @Router /workspace/{workspaceId}/toolbox/files [delete] // // @id FsDeleteFile func FsDeleteFile(ctx *gin.Context) { @@ -44,13 +42,12 @@ func FsDeleteFile(ctx *gin.Context) { // // @Tags workspace toolbox // @Summary Download file -// @Description Download file from workspace project +// @Description Download file from a workspace // @Produce json // @Param workspaceId path string true "Workspace ID or Name" -// @Param projectId path string true "Project ID" // @Param path query string true "Path" // @Success 200 {file} file "response contains the file" -// @Router /workspace/{workspaceId}/{projectId}/toolbox/files/download [get] +// @Router /workspace/{workspaceId}/toolbox/files/download [get] // // @id FsDownloadFile func FsDownloadFile(ctx *gin.Context) { @@ -61,14 +58,13 @@ func FsDownloadFile(ctx *gin.Context) { // // @Tags workspace toolbox // @Summary Search for text/pattern in files -// @Description Search for text/pattern inside workspace project files +// @Description Search for text/pattern inside a workspace files // @Produce json // @Param workspaceId path string true "Workspace ID or Name" -// @Param projectId path string true "Project ID" // @Param path query string true "Path" // @Param pattern query string true "Pattern" // @Success 200 {array} Match -// @Router /workspace/{workspaceId}/{projectId}/toolbox/files/find [get] +// @Router /workspace/{workspaceId}/toolbox/files/find [get] // // @id FsFindInFiles func FsFindInFiles(ctx *gin.Context) { @@ -79,13 +75,12 @@ func FsFindInFiles(ctx *gin.Context) { // // @Tags workspace toolbox // @Summary Get file info -// @Description Get file info inside workspace project +// @Description Get file info inside a workspace // @Produce json // @Param workspaceId path string true "Workspace ID or Name" -// @Param projectId path string true "Project ID" // @Param path query string true "Path" // @Success 200 {object} FileInfo -// @Router /workspace/{workspaceId}/{projectId}/toolbox/files/info [get] +// @Router /workspace/{workspaceId}/toolbox/files/info [get] // // @id FsGetFileDetails func FsGetFileDetails(ctx *gin.Context) { @@ -96,13 +91,12 @@ func FsGetFileDetails(ctx *gin.Context) { // // @Tags workspace toolbox // @Summary List files -// @Description List files inside workspace project +// @Description List files inside a workspace // @Produce json // @Param workspaceId path string true "Workspace ID or Name" -// @Param projectId path string true "Project ID" // @Param path query string false "Path" // @Success 200 {array} FileInfo -// @Router /workspace/{workspaceId}/{projectId}/toolbox/files [get] +// @Router /workspace/{workspaceId}/toolbox/files [get] // // @id FsListFiles func FsListFiles(ctx *gin.Context) { @@ -113,14 +107,13 @@ func FsListFiles(ctx *gin.Context) { // // @Tags workspace toolbox // @Summary Create folder -// @Description Create folder inside workspace project +// @Description Create folder inside a workspace // @Produce json // @Param workspaceId path string true "Workspace ID or Name" -// @Param projectId path string true "Project ID" // @Param source query string true "Source path" // @Param destination query string true "Destination path" // @Success 200 -// @Router /workspace/{workspaceId}/{projectId}/toolbox/files/move [post] +// @Router /workspace/{workspaceId}/toolbox/files/move [post] // // @id FsMoveFile func FsMoveFile(ctx *gin.Context) { @@ -131,13 +124,12 @@ func FsMoveFile(ctx *gin.Context) { // // @Tags workspace toolbox // @Summary Repleace text/pattern in files -// @Description Repleace text/pattern in mutilple files inside workspace project +// @Description Repleace text/pattern in mutilple files inside a workspace // @Produce json // @Param workspaceId path string true "Workspace ID or Name" -// @Param projectId path string true "Project ID" // @Param replace body ReplaceRequest true "ReplaceParams" // @Success 200 {array} ReplaceResult -// @Router /workspace/{workspaceId}/{projectId}/toolbox/files/replace [post] +// @Router /workspace/{workspaceId}/toolbox/files/replace [post] // // @id FsReplaceInFiles func FsReplaceInFiles(ctx *gin.Context) { @@ -148,14 +140,13 @@ func FsReplaceInFiles(ctx *gin.Context) { // // @Tags workspace toolbox // @Summary Search for files -// @Description Search for files inside workspace project +// @Description Search for files inside a workspace // @Produce json // @Param workspaceId path string true "Workspace ID or Name" -// @Param projectId path string true "Project ID" // @Param path query string true "Path" // @Param pattern query string true "Pattern" // @Success 200 {object} SearchFilesResponse -// @Router /workspace/{workspaceId}/{projectId}/toolbox/files/search [get] +// @Router /workspace/{workspaceId}/toolbox/files/search [get] // // @id FsSearchFiles func FsSearchFiles(ctx *gin.Context) { @@ -166,16 +157,15 @@ func FsSearchFiles(ctx *gin.Context) { // // @Tags workspace toolbox // @Summary Set file owner/group/permissions -// @Description Set file owner/group/permissions inside workspace project +// @Description Set file owner/group/permissions inside a workspace // @Produce json // @Param workspaceId path string true "Workspace ID or Name" -// @Param projectId path string true "Project ID" // @Param path query string true "Path" // @Param owner query string false "Owner" // @Param group query string false "Group" // @Param mode query string false "Mode" // @Success 200 -// @Router /workspace/{workspaceId}/{projectId}/toolbox/files/permissions [post] +// @Router /workspace/{workspaceId}/toolbox/files/permissions [post] // // @id FsSetFilePermissions func FsSetFilePermissions(ctx *gin.Context) { @@ -186,14 +176,13 @@ func FsSetFilePermissions(ctx *gin.Context) { // // @Tags workspace toolbox // @Summary Upload file -// @Description Upload file inside workspace project +// @Description Upload file inside a workspace // @Produce json // @Param workspaceId path string true "Workspace ID or Name" -// @Param projectId path string true "Project ID" // @Param path query string true "Path" // @Param file formData file true "File" // @Success 200 -// @Router /workspace/{workspaceId}/{projectId}/toolbox/files/upload [post] +// @Router /workspace/{workspaceId}/toolbox/files/upload [post] // // @id FsUploadFile func FsUploadFile(ctx *gin.Context) { diff --git a/pkg/api/controllers/workspace/toolbox/git.go b/pkg/api/controllers/workspace/toolbox/git.go index ac25efb75a..62f81f6e0e 100644 --- a/pkg/api/controllers/workspace/toolbox/git.go +++ b/pkg/api/controllers/workspace/toolbox/git.go @@ -12,10 +12,9 @@ import "github.com/gin-gonic/gin" // @Description Add files to git commit // @Produce json // @Param workspaceId path string true "Workspace ID or Name" -// @Param projectId path string true "Project ID" // @Param params body GitAddRequest true "GitAddRequest" // @Success 200 -// @Router /workspace/{workspaceId}/{projectId}/toolbox/git/add [post] +// @Router /workspace/{workspaceId}/toolbox/git/add [post] // // @id GitAddFiles func GitAddFiles(ctx *gin.Context) { @@ -26,13 +25,12 @@ func GitAddFiles(ctx *gin.Context) { // // @Tags workspace toolbox // @Summary Clone git repository -// @Description Clone git repository inside workspace project +// @Description Clone git repository inside a workspace // @Produce json // @Param workspaceId path string true "Workspace ID or Name" -// @Param projectId path string true "Project ID" // @Param params body GitCloneRequest true "GitCloneRequest" // @Success 200 -// @Router /workspace/{workspaceId}/{projectId}/toolbox/git/clone [post] +// @Router /workspace/{workspaceId}/toolbox/git/clone [post] // // @id GitCloneRepository func GitCloneRepository(ctx *gin.Context) { @@ -43,13 +41,12 @@ func GitCloneRepository(ctx *gin.Context) { // // @Tags workspace toolbox // @Summary Commit changes -// @Description Commit changes to git repository inside workspace project +// @Description Commit changes to git repository inside a workspace // @Produce json // @Param workspaceId path string true "Workspace ID or Name" -// @Param projectId path string true "Project ID" // @Param params body GitCommitRequest true "GitCommitRequest" // @Success 200 {object} GitCommitResponse -// @Router /workspace/{workspaceId}/{projectId}/toolbox/git/commit [post] +// @Router /workspace/{workspaceId}/toolbox/git/commit [post] // // @id GitCommitChanges func GitCommitChanges(ctx *gin.Context) { @@ -60,13 +57,12 @@ func GitCommitChanges(ctx *gin.Context) { // // @Tags workspace toolbox // @Summary Create branch -// @Description Create branch on git repository inside workspace project +// @Description Create branch on git repository inside a workspace // @Produce json // @Param workspaceId path string true "Workspace ID or Name" -// @Param projectId path string true "Project ID" // @Param params body GitBranchRequest true "GitBranchRequest" // @Success 201 -// @Router /workspace/{workspaceId}/{projectId}/toolbox/git/branches [post] +// @Router /workspace/{workspaceId}/toolbox/git/branches [post] // // @id GitCreateBranch func GitCreateBranch(ctx *gin.Context) { @@ -77,13 +73,12 @@ func GitCreateBranch(ctx *gin.Context) { // // @Tags workspace toolbox // @Summary Get commit history -// @Description Get commit history from git repository inside workspace project +// @Description Get commit history from git repository inside a workspace // @Produce json // @Param workspaceId path string true "Workspace ID or Name" -// @Param projectId path string true "Project ID" // @Param path query string true "Path to git repository" // @Success 200 {array} GitCommitInfo -// @Router /workspace/{workspaceId}/{projectId}/toolbox/git/history [get] +// @Router /workspace/{workspaceId}/toolbox/git/history [get] // // @id GitCommitHistory func GitCommitHistory(ctx *gin.Context) { @@ -94,13 +89,12 @@ func GitCommitHistory(ctx *gin.Context) { // // @Tags workspace toolbox // @Summary Get branch list -// @Description Get branch list from git repository inside workspace project +// @Description Get branch list from git repository inside a workspace // @Produce json // @Param workspaceId path string true "Workspace ID or Name" -// @Param projectId path string true "Project ID" // @Param path query string true "Path to git repository" // @Success 200 {object} ListBranchResponse -// @Router /workspace/{workspaceId}/{projectId}/toolbox/git/branches [get] +// @Router /workspace/{workspaceId}/toolbox/git/branches [get] // // @id GitBranchList func GitBranchList(ctx *gin.Context) { @@ -111,13 +105,12 @@ func GitBranchList(ctx *gin.Context) { // // @Tags workspace toolbox // @Summary Pull changes -// @Description Pull changes from remote to git repository inside workspace project +// @Description Pull changes from remote to git repository inside a workspace // @Produce json // @Param workspaceId path string true "Workspace ID or Name" -// @Param projectId path string true "Project ID" // @Param params body GitRepoRequest true "Git pull request" // @Success 200 -// @Router /workspace/{workspaceId}/{projectId}/toolbox/git/pull [post] +// @Router /workspace/{workspaceId}/toolbox/git/pull [post] // // @id GitPullChanges func GitPullChanges(ctx *gin.Context) { @@ -128,13 +121,12 @@ func GitPullChanges(ctx *gin.Context) { // // @Tags workspace toolbox // @Summary Push changes -// @Description Push changes to remote from git repository inside workspace project +// @Description Push changes to remote from git repository inside a workspace // @Produce json // @Param workspaceId path string true "Workspace ID or Name" -// @Param projectId path string true "Project ID" // @Param params body GitRepoRequest true "Git push request" // @Success 200 -// @Router /workspace/{workspaceId}/{projectId}/toolbox/git/push [post] +// @Router /workspace/{workspaceId}/toolbox/git/push [post] // // @id GitPushChanges func GitPushChanges(ctx *gin.Context) { @@ -145,13 +137,12 @@ func GitPushChanges(ctx *gin.Context) { // // @Tags workspace toolbox // @Summary Get git status -// @Description Get status from git repository inside workspace project +// @Description Get status from git repository inside a workspace // @Produce json // @Param workspaceId path string true "Workspace ID or Name" -// @Param projectId path string true "Project ID" // @Param path query string true "Path to git repository" // @Success 200 {object} GitStatus -// @Router /workspace/{workspaceId}/{projectId}/toolbox/git/status [get] +// @Router /workspace/{workspaceId}/toolbox/git/status [get] // // @id GitGitStatus func GitStatus(ctx *gin.Context) { diff --git a/pkg/api/controllers/workspace/toolbox/lsp.go b/pkg/api/controllers/workspace/toolbox/lsp.go index 24640d835d..5f77b10e0a 100644 --- a/pkg/api/controllers/workspace/toolbox/lsp.go +++ b/pkg/api/controllers/workspace/toolbox/lsp.go @@ -9,13 +9,12 @@ import "github.com/gin-gonic/gin" // // @Tags workspace toolbox // @Summary Start Lsp server -// @Description Start Lsp server process inside workspace project +// @Description Start Lsp server process inside a workspace // @Produce json // @Param workspaceId path string true "Workspace ID or Name" -// @Param projectId path string true "Project ID" // @Param params body LspServerRequest true "LspServerRequest" // @Success 200 -// @Router /workspace/{workspaceId}/{projectId}/toolbox/lsp/start [post] +// @Router /workspace/{workspaceId}/toolbox/lsp/start [post] // // @id LspStart func LspStart(ctx *gin.Context) { @@ -26,13 +25,12 @@ func LspStart(ctx *gin.Context) { // // @Tags workspace toolbox // @Summary Stop Lsp server -// @Description Stop Lsp server process inside workspace project +// @Description Stop Lsp server process inside a workspace // @Produce json // @Param workspaceId path string true "Workspace ID or Name" -// @Param projectId path string true "Project ID" // @Param params body LspServerRequest true "LspServerRequest" // @Success 200 -// @Router /workspace/{workspaceId}/{projectId}/toolbox/lsp/stop [post] +// @Router /workspace/{workspaceId}/toolbox/lsp/stop [post] // // @id LspStop func LspStop(ctx *gin.Context) { @@ -46,10 +44,9 @@ func LspStop(ctx *gin.Context) { // @Description The document open notification is sent from the client to the server to signal newly opened text documents. // @Produce json // @Param workspaceId path string true "Workspace ID or Name" -// @Param projectId path string true "Project ID" // @Param params body LspDocumentRequest true "LspDocumentRequest" // @Success 200 -// @Router /workspace/{workspaceId}/{projectId}/toolbox/lsp/did-open [post] +// @Router /workspace/{workspaceId}/toolbox/lsp/did-open [post] // // @id LspDidOpen func LspDidOpen(ctx *gin.Context) { @@ -63,10 +60,9 @@ func LspDidOpen(ctx *gin.Context) { // @Description The document close notification is sent from the client to the server when the document got closed in the client. // @Produce json // @Param workspaceId path string true "Workspace ID or Name" -// @Param projectId path string true "Project ID" // @Param params body LspDocumentRequest true "LspDocumentRequest" // @Success 200 -// @Router /workspace/{workspaceId}/{projectId}/toolbox/lsp/did-close [post] +// @Router /workspace/{workspaceId}/toolbox/lsp/did-close [post] // // @id LspDidClose func LspDidClose(ctx *gin.Context) { @@ -80,12 +76,11 @@ func LspDidClose(ctx *gin.Context) { // @Description The document symbol request is sent from the client to the server. // @Produce json // @Param workspaceId path string true "Workspace ID or Name" -// @Param projectId path string true "Project ID" // @Param languageId query string true "Language ID" // @Param pathToProject query string true "Path to project" // @Param uri query string true "Document Uri" // @Success 200 {array} LspSymbol -// @Router /workspace/{workspaceId}/{projectId}/toolbox/lsp/document-symbols [get] +// @Router /workspace/{workspaceId}/toolbox/lsp/document-symbols [get] // // @id LspDocumentSymbols func LspDocumentSymbols(ctx *gin.Context) { @@ -99,12 +94,11 @@ func LspDocumentSymbols(ctx *gin.Context) { // @Description The workspace symbol request is sent from the client to the server to list project-wide symbols matching the query string. // @Produce json // @Param workspaceId path string true "Workspace ID or Name" -// @Param projectId path string true "Project ID" // @Param languageId query string true "Language ID" // @Param pathToProject query string true "Path to project" // @Param query query string true "Symbol Query" // @Success 200 {array} LspSymbol -// @Router /workspace/{workspaceId}/{projectId}/toolbox/lsp/workspace-symbols [get] +// @Router /workspace/{workspaceId}/toolbox/lsp/workspace-symbols [get] // // @id LspWorkspaceSymbols func LspWorkspaceSymbols(ctx *gin.Context) { @@ -118,10 +112,9 @@ func LspWorkspaceSymbols(ctx *gin.Context) { // @Description The Completion request is sent from the client to the server to compute completion items at a given cursor position. // @Produce json // @Param workspaceId path string true "Workspace ID or Name" -// @Param projectId path string true "Project ID" // @Param params body LspCompletionParams true "LspCompletionParams" // @Success 200 {object} CompletionList -// @Router /workspace/{workspaceId}/{projectId}/toolbox/lsp/completions [post] +// @Router /workspace/{workspaceId}/toolbox/lsp/completions [post] // // @id LspCompletions func LspCompletions(ctx *gin.Context) { diff --git a/pkg/api/controllers/workspace/toolbox/process.go b/pkg/api/controllers/workspace/toolbox/process.go index 2d87730cdc..073252a43a 100644 --- a/pkg/api/controllers/workspace/toolbox/process.go +++ b/pkg/api/controllers/workspace/toolbox/process.go @@ -9,13 +9,12 @@ import "github.com/gin-gonic/gin" // // @Tags workspace toolbox // @Summary Execute command -// @Description Execute command synchronously inside workspace project +// @Description Execute command synchronously inside a workspace // @Produce json // @Param workspaceId path string true "Workspace ID or Name" -// @Param projectId path string true "Project ID" // @Param params body ExecuteRequest true "Execute command request" // @Success 200 {object} ExecuteResponse -// @Router /workspace/{workspaceId}/{projectId}/toolbox/process/execute [post] +// @Router /workspace/{workspaceId}/toolbox/process/execute [post] // // @id ProcessExecuteCommand func ProcessExecuteCommand(ctx *gin.Context) { diff --git a/pkg/api/controllers/workspace/toolbox/session.go b/pkg/api/controllers/workspace/toolbox/session.go index 80d078f813..de194181d4 100644 --- a/pkg/api/controllers/workspace/toolbox/session.go +++ b/pkg/api/controllers/workspace/toolbox/session.go @@ -12,10 +12,9 @@ import "github.com/gin-gonic/gin" // @Description Create exec session inside workspace project // @Produce json // @Param workspaceId path string true "Workspace ID or Name" -// @Param projectId path string true "Project ID" // @Param params body CreateSessionRequest true "Create session request" // @Success 201 -// @Router /workspace/{workspaceId}/{projectId}/toolbox/process/session [post] +// @Router /workspace/{workspaceId}/toolbox/process/session [post] // // @id CreateSession func CreateSession(ctx *gin.Context) { @@ -29,11 +28,10 @@ func CreateSession(ctx *gin.Context) { // @Description Execute command inside a session inside workspace project // @Produce json // @Param workspaceId path string true "Workspace ID or Name" -// @Param projectId path string true "Project ID" // @Param sessionId path string true "Session ID" // @Param params body SessionExecuteRequest true "Execute command request" // @Success 200 {object} SessionExecuteResponse -// @Router /workspace/{workspaceId}/{projectId}/toolbox/process/session/{sessionId}/exec [post] +// @Router /workspace/{workspaceId}/toolbox/process/session/{sessionId}/exec [post] // // @id SessionExecuteCommand func SessionExecuteCommand(ctx *gin.Context) { @@ -47,10 +45,9 @@ func SessionExecuteCommand(ctx *gin.Context) { // @Description Delete a session inside workspace project // @Produce json // @Param workspaceId path string true "Workspace ID or Name" -// @Param projectId path string true "Project ID" // @Param sessionId path string true "Session ID" // @Success 204 -// @Router /workspace/{workspaceId}/{projectId}/toolbox/process/session/{sessionId} [delete] +// @Router /workspace/{workspaceId}/toolbox/process/session/{sessionId} [delete] // // @id DeleteSession func DeleteSession(ctx *gin.Context) { @@ -64,9 +61,8 @@ func DeleteSession(ctx *gin.Context) { // @Description List sessions inside workspace project // @Produce json // @Param workspaceId path string true "Workspace ID or Name" -// @Param projectId path string true "Project ID" // @Success 200 {array} Session -// @Router /workspace/{workspaceId}/{projectId}/toolbox/process/session [get] +// @Router /workspace/{workspaceId}/toolbox/process/session [get] // // @id ListSessions func ListSessions(ctx *gin.Context) { @@ -80,11 +76,10 @@ func ListSessions(ctx *gin.Context) { // @Description Get logs of a command inside a session inside workspace project // @Description Connect with websocket to get a stream of the logs // @Param workspaceId path string true "Workspace ID or Name" -// @Param projectId path string true "Project ID" // @Param sessionId path string true "Session ID" // @Param commandId path string true "Command ID" // @Success 200 {string} string "command logs" -// @Router /workspace/{workspaceId}/{projectId}/toolbox/process/session/{sessionId}/command/{commandId}/logs [get] +// @Router /workspace/{workspaceId}/toolbox/process/session/{sessionId}/command/{commandId}/logs [get] // // @id GetSessionCommandLogs func GetSessionCommandLogs(ctx *gin.Context) { diff --git a/pkg/api/controllers/workspace/toolbox/toolbox.go b/pkg/api/controllers/workspace/toolbox/toolbox.go index 54acf1ff34..3c3cbcacf5 100644 --- a/pkg/api/controllers/workspace/toolbox/toolbox.go +++ b/pkg/api/controllers/workspace/toolbox/toolbox.go @@ -5,7 +5,6 @@ package toolbox import ( "encoding/json" - "errors" "fmt" "io" "net" @@ -15,26 +14,26 @@ import ( "strings" "github.com/daytonaio/daytona/pkg/agent/toolbox/config" + "github.com/daytonaio/daytona/pkg/common" "github.com/daytonaio/daytona/pkg/server" - "github.com/daytonaio/daytona/pkg/server/workspaces" - "github.com/daytonaio/daytona/pkg/workspace/project" + "github.com/daytonaio/daytona/pkg/services" + "github.com/daytonaio/daytona/pkg/stores" "github.com/gin-gonic/gin" "github.com/gorilla/websocket" ) -// GetProjectDir godoc +// GetWorkspaceDir godoc // // @Tags workspace toolbox -// @Summary Get project dir -// @Description Get project directory +// @Summary Get workspace dir +// @Description Get workspace directory // @Produce json // @Param workspaceId path string true "Workspace ID or Name" -// @Param projectId path string true "Project ID" -// @Success 200 {object} ProjectDirResponse -// @Router /workspace/{workspaceId}/{projectId}/toolbox/project-dir [get] +// @Success 200 {object} WorkspaceDirResponse +// @Router /workspace/{workspaceId}/toolbox/workspace-dir [get] // -// @id GetProjectDir -func GetProjectDir(ctx *gin.Context) { +// @id GetWorkspaceDir +func GetWorkspaceDir(ctx *gin.Context) { forwardRequestToToolbox(ctx) } @@ -46,13 +45,12 @@ var upgrader = websocket.Upgrader{ func forwardRequestToToolbox(ctx *gin.Context) { workspaceId := ctx.Param("workspaceId") - projectId := ctx.Param("projectId") server := server.GetInstance(nil) - w, err := server.WorkspaceService.GetWorkspace(ctx.Request.Context(), workspaceId, true) + w, err := server.WorkspaceService.Find(ctx.Request.Context(), workspaceId, services.WorkspaceRetrievalParams{}) if err != nil { - if workspaces.IsWorkspaceNotFound(err) { + if stores.IsWorkspaceNotFound(err) { ctx.AbortWithError(http.StatusNotFound, err) return } @@ -60,34 +58,18 @@ func forwardRequestToToolbox(ctx *gin.Context) { return } - var projectInfo *project.ProjectInfo - found := false - for _, p := range w.Info.Projects { - if p.Name == projectId { - projectInfo = p - found = true - break - } - } - - if !found { - ctx.AbortWithError(http.StatusNotFound, errors.New("project not found")) - return - } - var client *http.Client var websocketDialer *websocket.Dialer - projectHostname := project.GetProjectHostname(w.Id, projectId) - route := strings.Replace(ctx.Request.URL.Path, fmt.Sprintf("/workspace/%s/%s/toolbox/", workspaceId, projectId), "", 1) + workspaceHostname := common.GetTailscaleHostname(w.Id) + route := strings.Replace(ctx.Request.URL.Path, fmt.Sprintf("/workspace/%s/toolbox/", workspaceId), "", 1) query := ctx.Request.URL.Query().Encode() scheme := "http" if ctx.Request.Header.Get("Upgrade") == "websocket" { scheme = "ws" } - - reqUrl := fmt.Sprintf("%s://%s:%d/%s?%s", scheme, projectHostname, config.TOOLBOX_API_PORT, route, query) + reqUrl := fmt.Sprintf("%s://%s:%d/%s?%s", scheme, workspaceHostname, config.TOOLBOX_API_PORT, route, query) client = server.TailscaleServer.HTTPClient() websocketDialer = &websocket.Dialer{ NetDial: func(network, addr string) (net.Conn, error) { @@ -95,9 +77,9 @@ func forwardRequestToToolbox(ctx *gin.Context) { }, } - if w.Target == "local" { + if common.IsLocalDockerTarget(w.Target.TargetConfig.ProviderInfo.Name, w.Target.TargetConfig.Options, w.Target.TargetConfig.ProviderInfo.RunnerId) && w.ProviderMetadata != nil && *w.ProviderMetadata != "" { var metadata map[string]interface{} - err := json.Unmarshal([]byte(projectInfo.ProviderMetadata), &metadata) + err := json.Unmarshal([]byte(*w.ProviderMetadata), &metadata) if err == nil { if toolboxPortString, ok := metadata["daytona.toolbox.api.hostPort"]; ok { toolboxPort, err := strconv.ParseUint(toolboxPortString.(string), 10, 16) diff --git a/pkg/api/controllers/workspace/workspace.go b/pkg/api/controllers/workspace/workspace.go index 7af518f924..6f09aa3855 100644 --- a/pkg/api/controllers/workspace/workspace.go +++ b/pkg/api/controllers/workspace/workspace.go @@ -4,50 +4,80 @@ package workspace import ( - "errors" + "encoding/json" "fmt" "net/http" - "strconv" + "github.com/daytonaio/daytona/pkg/api/util" + "github.com/daytonaio/daytona/pkg/models" "github.com/daytonaio/daytona/pkg/server" + "github.com/daytonaio/daytona/pkg/services" + "github.com/daytonaio/daytona/pkg/stores" "github.com/gin-gonic/gin" ) -// GetWorkspace godoc +// FindWorkspace godoc // // @Tags workspace -// @Summary Get workspace info -// @Description Get workspace info +// @Summary Find workspace +// @Description Find workspace // @Produce json // @Param workspaceId path string true "Workspace ID or Name" -// @Param verbose query bool false "Verbose" // @Success 200 {object} WorkspaceDTO // @Router /workspace/{workspaceId} [get] // -// @id GetWorkspace -func GetWorkspace(ctx *gin.Context) { +// @id FindWorkspace +func FindWorkspace(ctx *gin.Context) { workspaceId := ctx.Param("workspaceId") - verboseQuery := ctx.Query("verbose") - verbose := false - var err error + server := server.GetInstance(nil) - if verboseQuery != "" { - verbose, err = strconv.ParseBool(verboseQuery) - if err != nil { - ctx.AbortWithError(http.StatusBadRequest, errors.New("invalid value for verbose flag")) - return + w, err := server.WorkspaceService.Find(ctx.Request.Context(), workspaceId, services.WorkspaceRetrievalParams{}) + if err != nil { + statusCode := http.StatusInternalServerError + if stores.IsWorkspaceNotFound(err) || services.IsWorkspaceDeleted(err) { + statusCode = http.StatusNotFound } + ctx.AbortWithError(statusCode, fmt.Errorf("failed to find workspace: %w", err)) + return } + apiKeyType, ok := ctx.Get("apiKeyType") + if !ok || apiKeyType == models.ApiKeyTypeClient { + util.HideDaytonaEnvVars(&w.EnvVars) + util.HideDaytonaEnvVars(&w.Target.EnvVars) + w.ApiKey = "" + w.Target.ApiKey = "" + } + + ctx.JSON(200, w) +} + +// GetWorkspaceState godoc +// +// @Tags workspace +// @Summary Get workspace state +// @Description Get workspace state +// @Produce json +// @Param workspaceId path string true "Workspace ID or Name" +// @Success 200 {object} ResourceState +// @Router /workspace/{workspaceId}/state [get] +// +// @id GetWorkspaceState +func GetWorkspaceState(ctx *gin.Context) { + workspaceId := ctx.Param("workspaceId") server := server.GetInstance(nil) - w, err := server.WorkspaceService.GetWorkspace(ctx.Request.Context(), workspaceId, verbose) + w, err := server.WorkspaceService.Find(ctx.Request.Context(), workspaceId, services.WorkspaceRetrievalParams{}) if err != nil { - ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to get workspace: %w", err)) + statusCode := http.StatusInternalServerError + if stores.IsWorkspaceNotFound(err) || services.IsWorkspaceDeleted(err) { + statusCode = http.StatusNotFound + } + ctx.AbortWithError(statusCode, fmt.Errorf("failed to find workspace: %w", err)) return } - ctx.JSON(200, w) + ctx.JSON(200, w.State) } // ListWorkspaces godoc @@ -55,73 +85,44 @@ func GetWorkspace(ctx *gin.Context) { // @Tags workspace // @Summary List workspaces // @Description List workspaces +// @Param labels query string false "JSON encoded labels" // @Produce json // @Success 200 {array} WorkspaceDTO // @Router /workspace [get] -// @Param verbose query bool false "Verbose" // // @id ListWorkspaces func ListWorkspaces(ctx *gin.Context) { - verboseQuery := ctx.Query("verbose") - verbose := false - var err error + labelsQuery := ctx.Query("labels") + + var labels map[string]string - if verboseQuery != "" { - verbose, err = strconv.ParseBool(verboseQuery) + if labelsQuery != "" { + err := json.Unmarshal([]byte(labelsQuery), &labels) if err != nil { - ctx.AbortWithError(http.StatusBadRequest, errors.New("invalid value for verbose flag")) + ctx.AbortWithError(http.StatusBadRequest, fmt.Errorf("invalid filters: %w", err)) return } } server := server.GetInstance(nil) - workspaceList, err := server.WorkspaceService.ListWorkspaces(ctx.Request.Context(), verbose) + workspaceList, err := server.WorkspaceService.List(ctx.Request.Context(), services.WorkspaceRetrievalParams{ + Labels: labels, + }) if err != nil { ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to list workspaces: %w", err)) return } - ctx.JSON(200, workspaceList) -} - -// RemoveWorkspace godoc -// -// @Tags workspace -// @Summary Remove workspace -// @Description Remove workspace -// @Param workspaceId path string true "Workspace ID" -// @Param force query bool false "Force" -// @Success 200 -// @Router /workspace/{workspaceId} [delete] -// -// @id RemoveWorkspace -func RemoveWorkspace(ctx *gin.Context) { - workspaceId := ctx.Param("workspaceId") - forceQuery := ctx.Query("force") - var err error - force := false - - if forceQuery != "" { - force, err = strconv.ParseBool(forceQuery) - if err != nil { - ctx.AbortWithError(http.StatusBadRequest, errors.New("invalid value for force flag")) - return + apiKeyType, ok := ctx.Get("apiKeyType") + if !ok || apiKeyType == models.ApiKeyTypeClient { + for i := range workspaceList { + util.HideDaytonaEnvVars(&workspaceList[i].EnvVars) + util.HideDaytonaEnvVars(&workspaceList[i].Target.EnvVars) + workspaceList[i].ApiKey = "" + workspaceList[i].Target.ApiKey = "" } } - server := server.GetInstance(nil) - - if force { - err = server.WorkspaceService.ForceRemoveWorkspace(ctx.Request.Context(), workspaceId) - } else { - err = server.WorkspaceService.RemoveWorkspace(ctx.Request.Context(), workspaceId) - } - - if err != nil { - ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to remove workspace: %w", err)) - return - } - - ctx.Status(200) + ctx.JSON(200, workspaceList) } diff --git a/pkg/api/controllers/workspacetemplate/prebuild/prebuild.go b/pkg/api/controllers/workspacetemplate/prebuild/prebuild.go new file mode 100644 index 0000000000..0d52fae5df --- /dev/null +++ b/pkg/api/controllers/workspacetemplate/prebuild/prebuild.go @@ -0,0 +1,181 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package prebuild + +import ( + "errors" + "fmt" + "net/http" + "strconv" + + "github.com/daytonaio/daytona/pkg/server" + "github.com/daytonaio/daytona/pkg/services" + "github.com/daytonaio/daytona/pkg/stores" + "github.com/gin-gonic/gin" +) + +// FindPrebuild godoc +// +// @Tags prebuild +// @Summary Find prebuild +// @Description Find prebuild +// @Accept json +// @Param templateName path string true "Workspace template name" +// @Param prebuildId path string true "Prebuild ID" +// @Success 200 {object} PrebuildDTO +// @Router /workspace-template/{templateName}/prebuild/{prebuildId} [get] +// +// @id FindPrebuild +func FindPrebuild(ctx *gin.Context) { + templateName := ctx.Param("templateName") + prebuildId := ctx.Param("prebuildId") + + server := server.GetInstance(nil) + res, err := server.WorkspaceTemplateService.FindPrebuild(ctx.Request.Context(), &stores.WorkspaceTemplateFilter{ + Name: &templateName, + }, &stores.PrebuildFilter{ + Id: &prebuildId, + }) + if err != nil { + if stores.IsPrebuildNotFound(err) { + ctx.AbortWithError(http.StatusNotFound, errors.New("prebuild not found")) + return + } + ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to get prebuild: %s", err.Error())) + return + } + + ctx.JSON(200, res) +} + +// SavePrebuild godoc + +// @Tags prebuild +// @Summary Save prebuild +// @Description Save prebuild +// @Accept json +// @Param templateName path string true "Template name" +// @Param prebuild body CreatePrebuildDTO true "Prebuild" +// @Success 201 {string} prebuildId +// @Router /workspace-template/{templateName}/prebuild [put] +// +// @id SavePrebuild +func SavePrebuild(ctx *gin.Context) { + templateName := ctx.Param("templateName") + + var dto services.CreatePrebuildDTO + err := ctx.BindJSON(&dto) + if err != nil { + ctx.AbortWithError(http.StatusBadRequest, fmt.Errorf("invalid request body: %s", err.Error())) + return + } + + server := server.GetInstance(nil) + prebuild, err := server.WorkspaceTemplateService.SavePrebuild(ctx.Request.Context(), templateName, dto) + if err != nil { + ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to set prebuild: %s", err.Error())) + return + } + + ctx.String(201, prebuild.Id) +} + +// ListPrebuilds godoc + +// @Tags prebuild +// @Summary List prebuilds +// @Description List prebuilds +// @Accept json +// @Success 200 {array} PrebuildDTO +// @Router /workspace-template/prebuild [get] +// +// @id ListPrebuilds +func ListPrebuilds(ctx *gin.Context) { + server := server.GetInstance(nil) + res, err := server.WorkspaceTemplateService.ListPrebuilds(ctx.Request.Context(), nil, nil) + if err != nil { + ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to get prebuilds: %s", err.Error())) + return + } + + ctx.JSON(200, res) +} + +// ListPrebuildsForWorkspaceTemplate godoc + +// @Tags prebuild +// @Summary List prebuilds for workspace template +// @Description List prebuilds for workspace template +// @Accept json +// @Param templateName path string true "Template name" +// @Success 200 {array} PrebuildDTO +// @Router /workspace-template/{templateName}/prebuild [get] +// +// @id ListPrebuildsForWorkspaceTemplate +func ListPrebuildsForWorkspaceTemplate(ctx *gin.Context) { + templateName := ctx.Param("templateName") + + var workspaceTemplateFilter *stores.WorkspaceTemplateFilter + + if templateName != "" { + workspaceTemplateFilter = &stores.WorkspaceTemplateFilter{ + Name: &templateName, + } + } + + server := server.GetInstance(nil) + res, err := server.WorkspaceTemplateService.ListPrebuilds(ctx.Request.Context(), workspaceTemplateFilter, nil) + if err != nil { + ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to get prebuilds: %s", err.Error())) + return + } + + ctx.JSON(200, res) +} + +// DeletePrebuild godoc +// +// @Tags prebuild +// @Summary Delete prebuild +// @Description Delete prebuild +// @Accept json +// @Param templateName path string true "Workspace template name" +// @Param prebuildId path string true "Prebuild ID" +// @Param force query bool false "Force" +// @Success 204 +// @Router /workspace-template/{templateName}/prebuild/{prebuildId} [delete] +// +// @id DeletePrebuild +func DeletePrebuild(ctx *gin.Context) { + templateName := ctx.Param("templateName") + prebuildId := ctx.Param("prebuildId") + forceQuery := ctx.Query("force") + + var err error + var force bool + + if forceQuery != "" { + force, err = strconv.ParseBool(forceQuery) + if err != nil { + ctx.AbortWithError(http.StatusBadRequest, errors.New("invalid value for force flag")) + return + } + } + + server := server.GetInstance(nil) + errs := server.WorkspaceTemplateService.DeletePrebuild(ctx.Request.Context(), templateName, prebuildId, force) + if len(errs) > 0 { + if stores.IsPrebuildNotFound(errs[0]) { + ctx.AbortWithError(http.StatusNotFound, errors.New("prebuild not found")) + return + } + for _, err := range errs { + _ = ctx.Error(err) + } + ctx.AbortWithStatus(http.StatusInternalServerError) + return + } + + ctx.Status(204) +} diff --git a/pkg/api/controllers/projectconfig/prebuild/process_git_event.go b/pkg/api/controllers/workspacetemplate/prebuild/process_git_event.go similarity index 80% rename from pkg/api/controllers/projectconfig/prebuild/process_git_event.go rename to pkg/api/controllers/workspacetemplate/prebuild/process_git_event.go index 08c656007e..85a66418b6 100644 --- a/pkg/api/controllers/projectconfig/prebuild/process_git_event.go +++ b/pkg/api/controllers/workspacetemplate/prebuild/process_git_event.go @@ -17,15 +17,15 @@ import ( // @Tags prebuild // @Summary ProcessGitEvent // @Description ProcessGitEvent -// @Param workspace body interface{} true "Webhook event" +// @Param body body interface{} true "Webhook event" // @Success 200 -// @Router /project-config/prebuild/process-git-event [post] +// @Router /workspace-template/prebuild/process-git-event [post] // // @id ProcessGitEvent func ProcessGitEvent(ctx *gin.Context) { server := server.GetInstance(nil) - gitProvider, err := server.GitProviderService.GetGitProviderForHttpRequest(ctx.Request) + gitProvider, err := server.GitProviderService.GetGitProviderForHttpRequest(ctx.Request.Context(), ctx.Request) if err != nil { ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to get git provider for request: %s", err.Error())) return @@ -41,7 +41,7 @@ func ProcessGitEvent(ctx *gin.Context) { return } - err = server.ProjectConfigService.ProcessGitEvent(*gitEventData) + err = server.WorkspaceTemplateService.ProcessGitEvent(ctx.Request.Context(), *gitEventData) if err != nil { ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to process git event: %s", err.Error())) return diff --git a/pkg/api/controllers/workspacetemplate/workspace_template.go b/pkg/api/controllers/workspacetemplate/workspace_template.go new file mode 100644 index 0000000000..4b9997048a --- /dev/null +++ b/pkg/api/controllers/workspacetemplate/workspace_template.go @@ -0,0 +1,232 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package workspacetemplate + +import ( + "errors" + "fmt" + "net/http" + "net/url" + "strconv" + + "github.com/daytonaio/daytona/internal/util" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/server" + "github.com/daytonaio/daytona/pkg/services" + "github.com/daytonaio/daytona/pkg/stores" + "github.com/gin-gonic/gin" + log "github.com/sirupsen/logrus" +) + +// FindWorkspaceTemplate godoc +// +// @Tags workspace-template +// @Summary Find a workspace template +// @Description Find a workspace template +// @Accept json +// @Param templateName path string true "Template name" +// @Success 200 {object} WorkspaceTemplate +// @Router /workspace-template/{templateName} [get] +// +// @id FindWorkspaceTemplate +func FindWorkspaceTemplate(ctx *gin.Context) { + templateName := ctx.Param("templateName") + + server := server.GetInstance(nil) + + workspaceTemplate, err := server.WorkspaceTemplateService.Find(ctx.Request.Context(), &stores.WorkspaceTemplateFilter{ + Name: &templateName, + }) + if err != nil { + ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to get workspace template: %s", err.Error())) + return + } + + ctx.JSON(200, workspaceTemplate) +} + +// GetDefaultWorkspaceTemplate godoc +// +// @Tags workspace-template +// @Summary Get default workspace templates by git url +// @Description Get default workspace templates by git url +// @Produce json +// @Param gitUrl path string true "Git URL" +// @Success 200 {object} WorkspaceTemplate +// @Router /workspace-template/default/{gitUrl} [get] +// +// @id GetDefaultWorkspaceTemplate +func GetDefaultWorkspaceTemplate(ctx *gin.Context) { + gitUrl := ctx.Param("gitUrl") + + decodedURLParam, err := url.QueryUnescape(gitUrl) + if err != nil { + ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to decode query param: %s", err.Error())) + return + } + + server := server.GetInstance(nil) + + workspaceTemplate, err := server.WorkspaceTemplateService.Find(ctx.Request.Context(), &stores.WorkspaceTemplateFilter{ + Url: &decodedURLParam, + Default: util.Pointer(true), + }) + if err != nil { + statusCode := http.StatusInternalServerError + if stores.IsWorkspaceTemplateNotFound(err) { + statusCode = http.StatusNotFound + ctx.AbortWithStatus(statusCode) + log.Debugf("Workspace template not added for git url: %s", decodedURLParam) + return + } + ctx.AbortWithError(statusCode, fmt.Errorf("failed to find workspace template by git url: %s", err.Error())) + return + } + + ctx.JSON(200, workspaceTemplate) +} + +// ListWorkspaceTemplates godoc +// +// @Tags workspace-template +// @Summary List workspace templates +// @Description List workspace templates +// @Produce json +// @Success 200 {array} WorkspaceTemplate +// @Router /workspace-template [get] +// +// @id ListWorkspaceTemplates +func ListWorkspaceTemplates(ctx *gin.Context) { + server := server.GetInstance(nil) + + workspaceTemplates, err := server.WorkspaceTemplateService.List(ctx.Request.Context(), nil) + if err != nil { + ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to list workspace templates: %s", err.Error())) + return + } + + ctx.JSON(200, workspaceTemplates) +} + +// SaveWorkspaceTemplate godoc +// +// @Tags workspace-template +// @Summary Set workspace template data +// @Description Set workspace template data +// @Accept json +// @Param workspaceTemplate body CreateWorkspaceTemplateDTO true "Workspace template" +// @Success 201 +// @Router /workspace-template [put] +// +// @id SaveWorkspaceTemplate +func SaveWorkspaceTemplate(ctx *gin.Context) { + var req services.CreateWorkspaceTemplateDTO + err := ctx.BindJSON(&req) + if err != nil { + ctx.AbortWithError(http.StatusBadRequest, fmt.Errorf("invalid request body: %s", err.Error())) + return + } + + s := server.GetInstance(nil) + + workspaceTemplate := models.WorkspaceTemplate{ + Name: req.Name, + BuildConfig: req.BuildConfig, + RepositoryUrl: req.RepositoryUrl, + EnvVars: req.EnvVars, + GitProviderConfigId: req.GitProviderConfigId, + } + + if req.Image != nil { + workspaceTemplate.Image = *req.Image + } + + if req.User != nil { + workspaceTemplate.User = *req.User + } + + err = s.WorkspaceTemplateService.Save(ctx.Request.Context(), &workspaceTemplate) + if err != nil { + ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to save workspace template: %s", err.Error())) + return + } + + ctx.Status(201) +} + +// SetDefaultWorkspaceTemplate godoc +// +// @Tags workspace-template +// @Summary Set workspace template to default +// @Description Set workspace template to default +// @Param templateName path string true "Template name" +// @Success 200 +// @Router /workspace-template/{templateName}/set-default [patch] +// +// @id SetDefaultWorkspaceTemplate +func SetDefaultWorkspaceTemplate(ctx *gin.Context) { + templateName := ctx.Param("templateName") + + server := server.GetInstance(nil) + + err := server.WorkspaceTemplateService.SetDefault(ctx.Request.Context(), templateName) + if err != nil { + ctx.AbortWithError(http.StatusNotFound, fmt.Errorf("failed to set workspace template to default: %s", err.Error())) + return + } + + ctx.Status(200) +} + +// DeleteWorkspaceTemplate godoc +// +// @Tags workspace-template +// @Summary Delete workspace template data +// @Description Delete workspace template data +// @Param templateName path string true "Template name" +// @Param force query bool false "Force" +// @Success 204 +// @Router /workspace-template/{templateName} [delete] +// +// @id DeleteWorkspaceTemplate +func DeleteWorkspaceTemplate(ctx *gin.Context) { + templateName := ctx.Param("templateName") + forceQuery := ctx.Query("force") + + var err error + var force bool + + if forceQuery != "" { + force, err = strconv.ParseBool(forceQuery) + if err != nil { + ctx.AbortWithError(http.StatusBadRequest, errors.New("invalid value for force flag")) + return + } + } + + server := server.GetInstance(nil) + + workspaceTemplate, err := server.WorkspaceTemplateService.Find(ctx.Request.Context(), &stores.WorkspaceTemplateFilter{ + Name: &templateName, + }) + if err != nil { + ctx.AbortWithError(http.StatusNotFound, fmt.Errorf("failed to find workspace template: %s", err.Error())) + return + } + + errs := server.WorkspaceTemplateService.Delete(ctx.Request.Context(), workspaceTemplate.Name, force) + if len(errs) > 0 { + if stores.IsWorkspaceTemplateNotFound(errs[0]) { + ctx.AbortWithError(http.StatusNotFound, errors.New("workspace template not found")) + return + } + for _, err := range errs { + _ = ctx.Error(err) + } + ctx.AbortWithStatus(http.StatusInternalServerError) + return + } + + ctx.Status(204) +} diff --git a/pkg/api/docs/docs.go b/pkg/api/docs/docs.go index fa9765d94f..7845accf81 100644 --- a/pkg/api/docs/docs.go +++ b/pkg/api/docs/docs.go @@ -32,7 +32,7 @@ const docTemplate = `{ "schema": { "type": "array", "items": { - "$ref": "#/definitions/ApiKey" + "$ref": "#/definitions/ApiKeyViewDTO" } } } @@ -41,15 +41,15 @@ const docTemplate = `{ }, "/apikey/{apiKeyName}": { "post": { - "description": "Generate an API key", + "description": "Create an API key", "produces": [ "text/plain" ], "tags": [ "apiKey" ], - "summary": "Generate an API key", - "operationId": "GenerateApiKey", + "summary": "Create an API key", + "operationId": "CreateApiKey", "parameters": [ { "type": "string", @@ -69,12 +69,12 @@ const docTemplate = `{ } }, "delete": { - "description": "Revoke API key", + "description": "Delete API key", "tags": [ "apiKey" ], - "summary": "Revoke API key", - "operationId": "RevokeApiKey", + "summary": "Delete API key", + "operationId": "DeleteApiKey", "parameters": [ { "type": "string", @@ -108,7 +108,7 @@ const docTemplate = `{ "schema": { "type": "array", "items": { - "$ref": "#/definitions/Build" + "$ref": "#/definitions/BuildDTO" } } } @@ -196,17 +196,50 @@ const docTemplate = `{ } } }, + "/build/successful/{repoUrl}": { + "get": { + "description": "List successful builds for Git repository", + "produces": [ + "application/json" + ], + "tags": [ + "build" + ], + "summary": "List successful builds for Git repository", + "operationId": "ListSuccessfulBuilds", + "parameters": [ + { + "type": "string", + "description": "Repository URL", + "name": "repoUrl", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/BuildDTO" + } + } + } + } + } + }, "/build/{buildId}": { "get": { - "description": "Get build data", + "description": "Find build", "consumes": [ "application/json" ], "tags": [ "build" ], - "summary": "Get build data", - "operationId": "GetBuild", + "summary": "Find build", + "operationId": "FindBuild", "parameters": [ { "type": "string", @@ -220,7 +253,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/Build" + "$ref": "#/definitions/BuildDTO" } } } @@ -254,81 +287,83 @@ const docTemplate = `{ } } }, - "/container-registry": { + "/container-registry/{server}": { "get": { - "description": "List container registries", + "description": "Find container registry", "produces": [ "application/json" ], "tags": [ - "container-registry" + "container registry" + ], + "summary": "Find container registry", + "operationId": "FindContainerRegistry", + "parameters": [ + { + "type": "string", + "description": "Container registry server", + "name": "server", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Workspace ID or Name", + "name": "workspaceId", + "in": "query" + } ], - "summary": "List container registries", - "operationId": "ListContainerRegistries", "responses": { "200": { "description": "OK", "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/ContainerRegistry" - } + "$ref": "#/definitions/ContainerRegistry" } } } } }, - "/container-registry/{server}": { + "/env": { "get": { - "description": "Get container registry credentials", + "description": "List environment variables", "produces": [ "application/json" ], "tags": [ - "container-registry" - ], - "summary": "Get container registry credentials", - "operationId": "GetContainerRegistry", - "parameters": [ - { - "type": "string", - "description": "Container Registry server name", - "name": "server", - "in": "path", - "required": true - } + "envVar" ], + "summary": "List environment variables", + "operationId": "ListEnvironmentVariables", "responses": { "200": { "description": "OK", "schema": { - "$ref": "#/definitions/ContainerRegistry" + "type": "array", + "items": { + "$ref": "#/definitions/EnvironmentVariable" + } } } } }, "put": { - "description": "Set container registry credentials", + "description": "Save environment variable", + "consumes": [ + "application/json" + ], "tags": [ - "container-registry" + "envVar" ], - "summary": "Set container registry credentials", - "operationId": "SetContainerRegistry", + "summary": "Save environment variable", + "operationId": "SaveEnvironmentVariable", "parameters": [ { - "type": "string", - "description": "Container Registry server name", - "name": "server", - "in": "path", - "required": true - }, - { - "description": "Container Registry credentials to set", - "name": "containerRegistry", + "description": "Environment Variable", + "name": "environmentVariable", "in": "body", "required": true, "schema": { - "$ref": "#/definitions/ContainerRegistry" + "$ref": "#/definitions/EnvironmentVariable" } } ], @@ -337,19 +372,21 @@ const docTemplate = `{ "description": "Created" } } - }, + } + }, + "/env/{key}": { "delete": { - "description": "Remove a container registry credentials", + "description": "Delete environment variable", "tags": [ - "container-registry" + "envVar" ], - "summary": "Remove a container registry credentials", - "operationId": "RemoveContainerRegistry", + "summary": "Delete environment variable", + "operationId": "DeleteEnvironmentVariable", "parameters": [ { "type": "string", - "description": "Container Registry server name", - "name": "server", + "description": "Environment Variable Key", + "name": "key", "in": "path", "required": true } @@ -385,15 +422,15 @@ const docTemplate = `{ } }, "put": { - "description": "Set Git provider", + "description": "Save Git provider", "produces": [ "application/json" ], "tags": [ "gitProvider" ], - "summary": "Set Git provider", - "operationId": "SetGitProvider", + "summary": "Save Git provider", + "operationId": "SaveGitProvider", "parameters": [ { "description": "Git provider", @@ -511,15 +548,15 @@ const docTemplate = `{ }, "/gitprovider/id-for-url/{url}": { "get": { - "description": "Get Git provider ID", + "description": "Find Git provider ID", "produces": [ "text/plain" ], "tags": [ "gitProvider" ], - "summary": "Get Git provider ID", - "operationId": "GetGitProviderIdForUrl", + "summary": "Find Git provider ID", + "operationId": "FindGitProviderIdForUrl", "parameters": [ { "type": "string", @@ -541,15 +578,15 @@ const docTemplate = `{ }, "/gitprovider/{gitProviderId}": { "get": { - "description": "Get Git provider", + "description": "Find Git provider", "produces": [ "text/plain" ], "tags": [ "gitProvider" ], - "summary": "Get Git provider", - "operationId": "GetGitProvider", + "summary": "Find Git provider", + "operationId": "FindGitProvider", "parameters": [ { "type": "string", @@ -569,15 +606,15 @@ const docTemplate = `{ } }, "delete": { - "description": "Remove Git provider", + "description": "Delete Git provider", "produces": [ "application/json" ], "tags": [ "gitProvider" ], - "summary": "Remove Git provider", - "operationId": "RemoveGitProvider", + "summary": "Delete Git provider", + "operationId": "DeleteGitProvider", "parameters": [ { "type": "string", @@ -860,214 +897,190 @@ const docTemplate = `{ } } }, - "/profile": { + "/job": { "get": { - "description": "Get profile data", - "consumes": [ - "application/json" - ], - "tags": [ - "profile" - ], - "summary": "Get profile data", - "operationId": "GetProfileData", - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/ProfileData" - } - } - } - }, - "put": { - "description": "Set profile data", - "consumes": [ + "description": "List jobs", + "produces": [ "application/json" ], "tags": [ - "profile" + "job" ], - "summary": "Set profile data", - "operationId": "SetProfileData", + "summary": "List jobs", + "operationId": "ListJobs", "parameters": [ { - "description": "Profile data", - "name": "profileData", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/ProfileData" - } - } - ], - "responses": { - "201": { - "description": "Created" + "type": "array", + "items": { + "type": "string" + }, + "collectionFormat": "multi", + "description": "Job States", + "name": "states", + "in": "query" + }, + { + "type": "array", + "items": { + "type": "string" + }, + "collectionFormat": "multi", + "description": "Job Actions", + "name": "actions", + "in": "query" + }, + { + "type": "string", + "description": "Resource ID", + "name": "resourceId", + "in": "query" + }, + { + "type": "string", + "description": "Resource Type", + "name": "resourceType", + "in": "query" } - } - }, - "delete": { - "description": "Delete profile data", - "tags": [ - "profile" ], - "summary": "Delete profile data", - "operationId": "DeleteProfileData", "responses": { - "204": { - "description": "No Content" + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/Job" + } + } } } } }, - "/project-config": { + "/runner": { "get": { - "description": "List project configs", + "description": "List runners", "produces": [ "application/json" ], "tags": [ - "project-config" + "runner" ], - "summary": "List project configs", - "operationId": "ListProjectConfigs", + "summary": "List runners", + "operationId": "ListRunners", "responses": { "200": { "description": "OK", "schema": { "type": "array", "items": { - "$ref": "#/definitions/ProjectConfig" + "$ref": "#/definitions/RunnerDTO" } } } } }, - "put": { - "description": "Set project config data", - "consumes": [ + "post": { + "description": "Create a runner", + "produces": [ "application/json" ], "tags": [ - "project-config" + "runner" ], - "summary": "Set project config data", - "operationId": "SetProjectConfig", + "summary": "Create a runner", + "operationId": "CreateRunner", "parameters": [ { - "description": "Project config", - "name": "projectConfig", + "description": "Runner", + "name": "runner", "in": "body", "required": true, "schema": { - "$ref": "#/definitions/CreateProjectConfigDTO" + "$ref": "#/definitions/CreateRunnerDTO" } } ], "responses": { - "201": { - "description": "Created" + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/CreateRunnerResultDTO" + } } } } }, - "/project-config/default/{gitUrl}": { + "/runner/provider": { "get": { - "description": "Get project configs by git url", + "description": "List providers", "produces": [ "application/json" ], "tags": [ - "project-config" + "provider" ], - "summary": "Get project configs by git url", - "operationId": "GetDefaultProjectConfig", + "summary": "List providers", + "operationId": "ListProviders", "parameters": [ { "type": "string", - "description": "Git URL", - "name": "gitUrl", - "in": "path", - "required": true + "description": "Runner ID", + "name": "runnerId", + "in": "query" } ], "responses": { "200": { "description": "OK", "schema": { - "$ref": "#/definitions/ProjectConfig" + "type": "array", + "items": { + "$ref": "#/definitions/ProviderInfo" + } } } } } }, - "/project-config/prebuild": { + "/runner/provider/for-install": { "get": { - "description": "List prebuilds", - "consumes": [ + "description": "List providers available for installation", + "produces": [ "application/json" ], "tags": [ - "prebuild" + "provider" ], - "summary": "List prebuilds", - "operationId": "ListPrebuilds", + "summary": "List providers available for installation", + "operationId": "ListProvidersForInstall", "responses": { "200": { "description": "OK", "schema": { "type": "array", "items": { - "$ref": "#/definitions/PrebuildDTO" + "$ref": "#/definitions/ProviderDTO" } } } } } }, - "/project-config/prebuild/process-git-event": { - "post": { - "description": "ProcessGitEvent", - "tags": [ - "prebuild" - ], - "summary": "ProcessGitEvent", - "operationId": "ProcessGitEvent", - "parameters": [ - { - "description": "Webhook event", - "name": "workspace", - "in": "body", - "required": true, - "schema": { - "type": "object" - } - } - ], - "responses": { - "200": { - "description": "OK" - } - } - } - }, - "/project-config/{configName}": { + "/runner/{runnerId}": { "get": { - "description": "Get project config data", - "consumes": [ + "description": "Find a runner", + "produces": [ "application/json" ], "tags": [ - "project-config" + "runner" ], - "summary": "Get project config data", - "operationId": "GetProjectConfig", + "summary": "Find a runner", + "operationId": "FindRunner", "parameters": [ { "type": "string", - "description": "Config name", - "name": "configName", + "description": "Runner ID", + "name": "runnerId", "in": "path", "required": true } @@ -1076,56 +1089,50 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/ProjectConfig" + "$ref": "#/definitions/RunnerDTO" } } } }, "delete": { - "description": "Delete project config data", + "description": "Delete runner", "tags": [ - "project-config" + "runner" ], - "summary": "Delete project config data", - "operationId": "DeleteProjectConfig", + "summary": "Delete runner", + "operationId": "DeleteRunner", "parameters": [ { "type": "string", - "description": "Config name", - "name": "configName", + "description": "Runner ID", + "name": "runnerId", "in": "path", "required": true - }, - { - "type": "boolean", - "description": "Force", - "name": "force", - "in": "query" } ], "responses": { - "204": { - "description": "No Content" + "200": { + "description": "OK" } } } }, - "/project-config/{configName}/prebuild": { + "/runner/{runnerId}/jobs": { "get": { - "description": "List prebuilds for project config", - "consumes": [ + "description": "List runner jobs", + "produces": [ "application/json" ], "tags": [ - "prebuild" + "runner" ], - "summary": "List prebuilds for project config", - "operationId": "ListPrebuildsForProjectConfig", + "summary": "List runner jobs", + "operationId": "ListRunnerJobs", "parameters": [ { "type": "string", - "description": "Config name", - "name": "configName", + "description": "Runner ID", + "name": "runnerId", "in": "path", "required": true } @@ -1136,193 +1143,150 @@ const docTemplate = `{ "schema": { "type": "array", "items": { - "$ref": "#/definitions/PrebuildDTO" + "$ref": "#/definitions/Job" } } } } - }, - "put": { - "description": "Set prebuild", - "consumes": [ + } + }, + "/runner/{runnerId}/jobs/{jobId}/state": { + "post": { + "description": "Update job state", + "produces": [ "application/json" ], "tags": [ - "prebuild" + "runner" ], - "summary": "Set prebuild", - "operationId": "SetPrebuild", + "summary": "Update job state", + "operationId": "UpdateJobState", "parameters": [ { "type": "string", - "description": "Config name", - "name": "configName", + "description": "Runner ID", + "name": "runnerId", "in": "path", "required": true }, { - "description": "Prebuild", - "name": "prebuild", + "type": "string", + "description": "Job ID", + "name": "jobId", + "in": "path", + "required": true + }, + { + "description": "Update job state", + "name": "updateJobState", "in": "body", "required": true, "schema": { - "$ref": "#/definitions/CreatePrebuildDTO" + "$ref": "#/definitions/UpdateJobState" } } ], "responses": { - "201": { - "description": "Created", - "schema": { - "type": "string" - } + "200": { + "description": "OK" } } } }, - "/project-config/{configName}/prebuild/{prebuildId}": { - "get": { - "description": "Get prebuild", - "consumes": [ - "application/json" - ], + "/runner/{runnerId}/metadata": { + "post": { + "description": "Update runner metadata", "tags": [ - "prebuild" + "runner" ], - "summary": "Get prebuild", - "operationId": "GetPrebuild", + "summary": "Update runner metadata", + "operationId": "UpdateRunnerMetadata", "parameters": [ { "type": "string", - "description": "Project config name", - "name": "configName", + "description": "Runner ID", + "name": "runnerId", "in": "path", "required": true }, { - "type": "string", - "description": "Prebuild ID", - "name": "prebuildId", - "in": "path", - "required": true + "description": "Runner Metadata", + "name": "runnerMetadata", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/UpdateRunnerMetadataDTO" + } } ], "responses": { "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/PrebuildDTO" - } + "description": "OK" } } - }, - "delete": { - "description": "Delete prebuild", - "consumes": [ + } + }, + "/runner/{runnerId}/provider": { + "get": { + "description": "Get runner providers", + "produces": [ "application/json" ], "tags": [ - "prebuild" + "provider" ], - "summary": "Delete prebuild", - "operationId": "DeletePrebuild", + "summary": "Get runner providers", + "operationId": "GetRunnerProviders", "parameters": [ { "type": "string", - "description": "Project config name", - "name": "configName", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Prebuild ID", - "name": "prebuildId", - "in": "path", - "required": true - }, - { - "type": "boolean", - "description": "Force", - "name": "force", - "in": "query" - } - ], - "responses": { - "204": { - "description": "No Content" - } - } - } - }, - "/project-config/{configName}/set-default": { - "patch": { - "description": "Set project config to default", - "tags": [ - "project-config" - ], - "summary": "Set project config to default", - "operationId": "SetDefaultProjectConfig", - "parameters": [ - { - "type": "string", - "description": "Config name", - "name": "configName", + "description": "Runner ID", + "name": "runnerId", "in": "path", "required": true } ], - "responses": { - "200": { - "description": "OK" - } - } - } - }, - "/provider": { - "get": { - "description": "List providers", - "produces": [ - "application/json" - ], - "tags": [ - "provider" - ], - "summary": "List providers", - "operationId": "ListProviders", "responses": { "200": { "description": "OK", "schema": { "type": "array", "items": { - "$ref": "#/definitions/Provider" + "$ref": "#/definitions/ProviderInfo" } } } } } }, - "/provider/install": { + "/runner/{runnerId}/provider/{providerName}/install": { "post": { - "description": "Install a provider", - "consumes": [ - "application/json" - ], + "description": "Install provider", "tags": [ "provider" ], - "summary": "Install a provider", + "summary": "Install provider", "operationId": "InstallProvider", "parameters": [ { - "description": "Provider to install", - "name": "provider", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/InstallProviderRequest" - } + "type": "string", + "description": "Runner ID", + "name": "runnerId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Provider name", + "name": "providerName", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Provider version - defaults to 'latest'", + "name": "providerVersion", + "in": "query" } ], "responses": { @@ -1332,51 +1296,65 @@ const docTemplate = `{ } } }, - "/provider/{provider}/target-manifest": { - "get": { - "description": "Get provider target manifest", + "/runner/{runnerId}/provider/{providerName}/uninstall": { + "post": { + "description": "Uninstall provider", "tags": [ "provider" ], - "summary": "Get provider target manifest", - "operationId": "GetTargetManifest", + "summary": "Uninstall provider", + "operationId": "UninstallProvider", "parameters": [ + { + "type": "string", + "description": "Runner ID", + "name": "runnerId", + "in": "path", + "required": true + }, { "type": "string", "description": "Provider name", - "name": "provider", + "name": "providerName", "in": "path", "required": true } ], "responses": { "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/ProviderTargetManifest" - } + "description": "OK" } } } }, - "/provider/{provider}/uninstall": { + "/runner/{runnerId}/provider/{providerName}/update": { "post": { - "description": "Uninstall a provider", - "consumes": [ - "application/json" - ], + "description": "Update provider", "tags": [ "provider" ], - "summary": "Uninstall a provider", - "operationId": "UninstallProvider", + "summary": "Update provider", + "operationId": "UpdateProvider", "parameters": [ { "type": "string", - "description": "Provider to uninstall", - "name": "provider", + "description": "Runner ID", + "name": "runnerId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Provider name", + "name": "providerName", "in": "path", "required": true + }, + { + "type": "string", + "description": "Provider version - defaults to 'latest'", + "name": "providerVersion", + "in": "query" } ], "responses": { @@ -1430,8 +1408,8 @@ const docTemplate = `{ } } }, - "post": { - "description": "Set the server configuration", + "put": { + "description": "Save the server configuration", "consumes": [ "application/json" ], @@ -1441,8 +1419,8 @@ const docTemplate = `{ "tags": [ "server" ], - "summary": "Set the server configuration", - "operationId": "SetConfig", + "summary": "Save the server configuration", + "operationId": "SaveConfig", "parameters": [ { "description": "Server configuration", @@ -1466,14 +1444,14 @@ const docTemplate = `{ }, "/server/logs": { "get": { - "description": "List server log files", + "description": "Get server log files", "produces": [ "application/json" ], "tags": [ "server" ], - "summary": "List server log files", + "summary": "Get server log files", "operationId": "GetServerLogFiles", "responses": { "200": { @@ -1490,15 +1468,15 @@ const docTemplate = `{ }, "/server/network-key": { "post": { - "description": "Generate a new authentication key", + "description": "Create a new authentication key", "produces": [ "application/json" ], "tags": [ "server" ], - "summary": "Generate a new authentication key", - "operationId": "GenerateNetworkKey", + "summary": "Create a new authentication key", + "operationId": "CreateNetworkKey", "responses": { "200": { "description": "OK", @@ -1520,107 +1498,73 @@ const docTemplate = `{ ], "summary": "List targets", "operationId": "ListTargets", + "parameters": [ + { + "type": "boolean", + "description": "Show target config options", + "name": "showOptions", + "in": "query" + } + ], "responses": { "200": { "description": "OK", "schema": { "type": "array", "items": { - "$ref": "#/definitions/ProviderTarget" + "$ref": "#/definitions/TargetDTO" } } } } }, - "put": { - "description": "Set a target", + "post": { + "description": "Create a target", + "produces": [ + "application/json" + ], "tags": [ "target" ], - "summary": "Set a target", - "operationId": "SetTarget", + "summary": "Create a target", + "operationId": "CreateTarget", "parameters": [ { - "description": "Target to set", + "description": "Create target", "name": "target", "in": "body", "required": true, "schema": { - "$ref": "#/definitions/CreateProviderTargetDTO" + "$ref": "#/definitions/CreateTargetDTO" } } ], - "responses": { - "201": { - "description": "Created" - } - } - } - }, - "/target/{target}": { - "delete": { - "description": "Remove a target", - "tags": [ - "target" - ], - "summary": "Remove a target", - "operationId": "RemoveTarget", - "parameters": [ - { - "type": "string", - "description": "Target name", - "name": "target", - "in": "path", - "required": true - } - ], - "responses": { - "204": { - "description": "No Content" - } - } - } - }, - "/target/{target}/set-default": { - "patch": { - "description": "Set target to default", - "tags": [ - "target" - ], - "summary": "Set target to default", - "operationId": "SetDefaultTarget", - "parameters": [ - { - "type": "string", - "description": "Target name", - "name": "target", - "in": "path", - "required": true - } - ], "responses": { "200": { - "description": "OK" + "description": "OK", + "schema": { + "$ref": "#/definitions/Target" + } } } } }, - "/workspace": { + "/target-config": { "get": { - "description": "List workspaces", + "description": "List target configs", "produces": [ "application/json" ], "tags": [ - "workspace" + "target-config" ], - "summary": "List workspaces", - "operationId": "ListWorkspaces", + "summary": "List target configs", + "operationId": "ListTargetConfigs", "parameters": [ { "type": "boolean", - "description": "Verbose", - "name": "verbose", + "description": "Show target config options", + "name": "showOptions", "in": "query" } ], @@ -1630,66 +1574,93 @@ const docTemplate = `{ "schema": { "type": "array", "items": { - "$ref": "#/definitions/WorkspaceDTO" + "$ref": "#/definitions/TargetConfig" } } } } }, "post": { - "description": "Create a workspace", - "produces": [ - "application/json" - ], + "description": "Create a target config", "tags": [ - "workspace" + "target-config" ], - "summary": "Create a workspace", - "operationId": "CreateWorkspace", + "summary": "Create a target config", + "operationId": "CreateTargetConfig", "parameters": [ { - "description": "Create workspace", - "name": "workspace", + "description": "Target config to create", + "name": "targetConfig", "in": "body", "required": true, "schema": { - "$ref": "#/definitions/CreateWorkspaceDTO" + "$ref": "#/definitions/CreateTargetConfigDTO" } + }, + { + "type": "boolean", + "description": "Show target config options", + "name": "showOptions", + "in": "query" } ], "responses": { "200": { "description": "OK", "schema": { - "$ref": "#/definitions/Workspace" + "$ref": "#/definitions/TargetConfig" } } } } }, - "/workspace/{workspaceId}": { + "/target-config/{configId}": { + "delete": { + "description": "Delete a target config", + "tags": [ + "target-config" + ], + "summary": "Delete a target config", + "operationId": "DeleteTargetConfig", + "parameters": [ + { + "type": "string", + "description": "Target Config Id", + "name": "configId", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "No Content" + } + } + } + }, + "/target/{targetId}": { "get": { - "description": "Get workspace info", + "description": "Find target", "produces": [ "application/json" ], "tags": [ - "workspace" + "target" ], - "summary": "Get workspace info", - "operationId": "GetWorkspace", + "summary": "Find target", + "operationId": "FindTarget", "parameters": [ { "type": "string", - "description": "Workspace ID or Name", - "name": "workspaceId", + "description": "Target ID or Name", + "name": "targetId", "in": "path", "required": true }, { "type": "boolean", - "description": "Verbose", - "name": "verbose", + "description": "Show target config options", + "name": "showOptions", "in": "query" } ], @@ -1697,23 +1668,23 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/WorkspaceDTO" + "$ref": "#/definitions/TargetDTO" } } } }, "delete": { - "description": "Remove workspace", + "description": "Delete target", "tags": [ - "workspace" + "target" ], - "summary": "Remove workspace", - "operationId": "RemoveWorkspace", + "summary": "Delete target", + "operationId": "DeleteTarget", "parameters": [ { "type": "string", - "description": "Workspace ID", - "name": "workspaceId", + "description": "Target ID", + "name": "targetId", "in": "path", "required": true }, @@ -1731,19 +1702,19 @@ const docTemplate = `{ } } }, - "/workspace/{workspaceId}/start": { + "/target/{targetId}/handle-successful-creation": { "post": { - "description": "Start workspace", + "description": "Handles successful creation of the target", "tags": [ - "workspace" + "target" ], - "summary": "Start workspace", - "operationId": "StartWorkspace", + "summary": "Handles successful creation of the target", + "operationId": "HandleSuccessfulCreation", "parameters": [ { "type": "string", - "description": "Workspace ID or Name", - "name": "workspaceId", + "description": "Target ID or name", + "name": "targetId", "in": "path", "required": true } @@ -1755,21 +1726,30 @@ const docTemplate = `{ } } }, - "/workspace/{workspaceId}/stop": { + "/target/{targetId}/metadata": { "post": { - "description": "Stop workspace", + "description": "Update target metadata", "tags": [ - "workspace" + "target" ], - "summary": "Stop workspace", - "operationId": "StopWorkspace", + "summary": "Update target metadata", + "operationId": "UpdateTargetMetadata", "parameters": [ { "type": "string", - "description": "Workspace ID or Name", - "name": "workspaceId", + "description": "Target ID", + "name": "targetId", "in": "path", "required": true + }, + { + "description": "Target Metadata", + "name": "targetMetadata", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/UpdateTargetMetadataDTO" + } } ], "responses": { @@ -1779,28 +1759,30 @@ const docTemplate = `{ } } }, - "/workspace/{workspaceId}/{projectId}/start": { + "/target/{targetId}/provider-metadata": { "post": { - "description": "Start project", + "description": "Update target provider metadata", "tags": [ - "workspace" + "target" ], - "summary": "Start project", - "operationId": "StartProject", + "summary": "Update target provider metadata", + "operationId": "UpdateTargetProviderMetadata", "parameters": [ { "type": "string", - "description": "Workspace ID or Name", - "name": "workspaceId", + "description": "Target ID", + "name": "targetId", "in": "path", "required": true }, { - "type": "string", - "description": "Project ID", - "name": "projectId", - "in": "path", - "required": true + "description": "Provider metadata", + "name": "metadata", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/UpdateTargetProviderMetadataDTO" + } } ], "responses": { @@ -1810,37 +1792,21 @@ const docTemplate = `{ } } }, - "/workspace/{workspaceId}/{projectId}/state": { + "/target/{targetId}/restart": { "post": { - "description": "Set project state", + "description": "Restart target", "tags": [ - "workspace" + "target" ], - "summary": "Set project state", - "operationId": "SetProjectState", + "summary": "Restart target", + "operationId": "RestartTarget", "parameters": [ { "type": "string", - "description": "Workspace ID or Name", - "name": "workspaceId", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Project ID", - "name": "projectId", + "description": "Target ID or Name", + "name": "targetId", "in": "path", "required": true - }, - { - "description": "Set State", - "name": "setState", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/SetProjectState" - } } ], "responses": { @@ -1850,26 +1816,19 @@ const docTemplate = `{ } } }, - "/workspace/{workspaceId}/{projectId}/stop": { - "post": { - "description": "Stop project", + "/target/{targetId}/set-default": { + "patch": { + "description": "Set target to be used by default", "tags": [ - "workspace" + "target" ], - "summary": "Stop project", - "operationId": "StopProject", + "summary": "Set target to be used by default", + "operationId": "SetDefaultTarget", "parameters": [ { "type": "string", - "description": "Workspace ID or Name", - "name": "workspaceId", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Project ID", - "name": "projectId", + "description": "Target ID or name", + "name": "targetId", "in": "path", "required": true } @@ -1881,174 +1840,101 @@ const docTemplate = `{ } } }, - "/workspace/{workspaceId}/{projectId}/toolbox/files": { - "get": { - "description": "List files inside workspace project", - "produces": [ - "application/json" - ], + "/target/{targetId}/start": { + "post": { + "description": "Start target", "tags": [ - "workspace toolbox" + "target" ], - "summary": "List files", - "operationId": "FsListFiles", + "summary": "Start target", + "operationId": "StartTarget", "parameters": [ { "type": "string", - "description": "Workspace ID or Name", - "name": "workspaceId", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Project ID", - "name": "projectId", + "description": "Target ID or Name", + "name": "targetId", "in": "path", "required": true - }, - { - "type": "string", - "description": "Path", - "name": "path", - "in": "query" } ], "responses": { "200": { - "description": "OK", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/FileInfo" - } - } + "description": "OK" } } - }, - "delete": { - "description": "Delete file inside workspace project", + } + }, + "/target/{targetId}/state": { + "get": { + "description": "Get target state", "produces": [ "application/json" ], "tags": [ - "workspace toolbox" + "target" ], - "summary": "Delete file", - "operationId": "FsDeleteFile", + "summary": "Get target state", + "operationId": "GetTargetState", "parameters": [ { "type": "string", - "description": "Workspace ID or Name", - "name": "workspaceId", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Project ID", - "name": "projectId", + "description": "Target ID or Name", + "name": "targetId", "in": "path", "required": true - }, - { - "type": "string", - "description": "Path", - "name": "path", - "in": "query", - "required": true } ], "responses": { - "204": { - "description": "No Content" + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/ResourceState" + } } } } }, - "/workspace/{workspaceId}/{projectId}/toolbox/files/download": { - "get": { - "description": "Download file from workspace project", - "produces": [ - "application/json" - ], + "/target/{targetId}/stop": { + "post": { + "description": "Stop target", "tags": [ - "workspace toolbox" + "target" ], - "summary": "Download file", - "operationId": "FsDownloadFile", + "summary": "Stop target", + "operationId": "StopTarget", "parameters": [ { "type": "string", - "description": "Workspace ID or Name", - "name": "workspaceId", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Project ID", - "name": "projectId", + "description": "Target ID or Name", + "name": "targetId", "in": "path", "required": true - }, - { - "type": "string", - "description": "Path", - "name": "path", - "in": "query", - "required": true } ], "responses": { "200": { - "description": "response contains the file", - "schema": { - "type": "file" - } + "description": "OK" } } } }, - "/workspace/{workspaceId}/{projectId}/toolbox/files/find": { + "/workspace": { "get": { - "description": "Search for text/pattern inside workspace project files", + "description": "List workspaces", "produces": [ "application/json" ], "tags": [ - "workspace toolbox" + "workspace" ], - "summary": "Search for text/pattern in files", - "operationId": "FsFindInFiles", + "summary": "List workspaces", + "operationId": "ListWorkspaces", "parameters": [ { "type": "string", - "description": "Workspace ID or Name", - "name": "workspaceId", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Project ID", - "name": "projectId", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Path", - "name": "path", - "in": "query", - "required": true - }, - { - "type": "string", - "description": "Pattern", - "name": "pattern", - "in": "query", - "required": true + "description": "JSON encoded labels", + "name": "labels", + "in": "query" } ], "responses": { @@ -2057,522 +1943,392 @@ const docTemplate = `{ "schema": { "type": "array", "items": { - "$ref": "#/definitions/Match" + "$ref": "#/definitions/WorkspaceDTO" } } } } - } - }, - "/workspace/{workspaceId}/{projectId}/toolbox/files/folder": { + }, "post": { - "description": "Create folder inside workspace project", + "description": "Create a workspace", "produces": [ "application/json" ], "tags": [ - "workspace toolbox" + "workspace" ], - "summary": "Create folder", - "operationId": "FsCreateFolder", + "summary": "Create a workspace", + "operationId": "CreateWorkspace", "parameters": [ { - "type": "string", - "description": "Workspace ID or Name", - "name": "workspaceId", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Project ID", - "name": "projectId", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Path", - "name": "path", - "in": "query", - "required": true - }, - { - "type": "string", - "description": "Mode", - "name": "mode", - "in": "query", - "required": true + "description": "Create workspace", + "name": "workspace", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/CreateWorkspaceDTO" + } } ], "responses": { - "201": { - "description": "Created" + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/WorkspaceDTO" + } } } } }, - "/workspace/{workspaceId}/{projectId}/toolbox/files/info": { + "/workspace-template": { "get": { - "description": "Get file info inside workspace project", + "description": "List workspace templates", "produces": [ "application/json" ], "tags": [ - "workspace toolbox" - ], - "summary": "Get file info", - "operationId": "FsGetFileDetails", - "parameters": [ - { - "type": "string", - "description": "Workspace ID or Name", - "name": "workspaceId", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Project ID", - "name": "projectId", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Path", - "name": "path", - "in": "query", - "required": true - } + "workspace-template" ], + "summary": "List workspace templates", + "operationId": "ListWorkspaceTemplates", "responses": { "200": { "description": "OK", "schema": { - "$ref": "#/definitions/FileInfo" + "type": "array", + "items": { + "$ref": "#/definitions/WorkspaceTemplate" + } + } + } + } + }, + "put": { + "description": "Set workspace template data", + "consumes": [ + "application/json" + ], + "tags": [ + "workspace-template" + ], + "summary": "Set workspace template data", + "operationId": "SaveWorkspaceTemplate", + "parameters": [ + { + "description": "Workspace template", + "name": "workspaceTemplate", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/CreateWorkspaceTemplateDTO" } } + ], + "responses": { + "201": { + "description": "Created" + } } } }, - "/workspace/{workspaceId}/{projectId}/toolbox/files/move": { - "post": { - "description": "Create folder inside workspace project", + "/workspace-template/default/{gitUrl}": { + "get": { + "description": "Get default workspace templates by git url", "produces": [ "application/json" ], "tags": [ - "workspace toolbox" + "workspace-template" ], - "summary": "Create folder", - "operationId": "FsMoveFile", + "summary": "Get default workspace templates by git url", + "operationId": "GetDefaultWorkspaceTemplate", "parameters": [ { "type": "string", - "description": "Workspace ID or Name", - "name": "workspaceId", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Project ID", - "name": "projectId", + "description": "Git URL", + "name": "gitUrl", "in": "path", "required": true - }, - { - "type": "string", - "description": "Source path", - "name": "source", - "in": "query", - "required": true - }, - { - "type": "string", - "description": "Destination path", - "name": "destination", - "in": "query", - "required": true } ], "responses": { "200": { - "description": "OK" + "description": "OK", + "schema": { + "$ref": "#/definitions/WorkspaceTemplate" + } } } } }, - "/workspace/{workspaceId}/{projectId}/toolbox/files/permissions": { - "post": { - "description": "Set file owner/group/permissions inside workspace project", - "produces": [ + "/workspace-template/prebuild": { + "get": { + "description": "List prebuilds", + "consumes": [ "application/json" ], "tags": [ - "workspace toolbox" - ], - "summary": "Set file owner/group/permissions", - "operationId": "FsSetFilePermissions", - "parameters": [ - { - "type": "string", - "description": "Workspace ID or Name", - "name": "workspaceId", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Project ID", - "name": "projectId", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Path", - "name": "path", - "in": "query", - "required": true - }, - { - "type": "string", - "description": "Owner", - "name": "owner", - "in": "query" - }, - { - "type": "string", - "description": "Group", - "name": "group", - "in": "query" - }, - { - "type": "string", - "description": "Mode", - "name": "mode", - "in": "query" - } + "prebuild" ], + "summary": "List prebuilds", + "operationId": "ListPrebuilds", "responses": { "200": { - "description": "OK" + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/PrebuildDTO" + } + } } } } }, - "/workspace/{workspaceId}/{projectId}/toolbox/files/replace": { + "/workspace-template/prebuild/process-git-event": { "post": { - "description": "Repleace text/pattern in mutilple files inside workspace project", - "produces": [ - "application/json" - ], + "description": "ProcessGitEvent", "tags": [ - "workspace toolbox" + "prebuild" ], - "summary": "Repleace text/pattern in files", - "operationId": "FsReplaceInFiles", + "summary": "ProcessGitEvent", + "operationId": "ProcessGitEvent", "parameters": [ { - "type": "string", - "description": "Workspace ID or Name", - "name": "workspaceId", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Project ID", - "name": "projectId", - "in": "path", - "required": true - }, - { - "description": "ReplaceParams", - "name": "replace", + "description": "Webhook event", + "name": "body", "in": "body", "required": true, "schema": { - "$ref": "#/definitions/ReplaceRequest" + "type": "object" } } ], "responses": { "200": { - "description": "OK", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/ReplaceResult" - } - } + "description": "OK" } } } }, - "/workspace/{workspaceId}/{projectId}/toolbox/files/search": { + "/workspace-template/{templateName}": { "get": { - "description": "Search for files inside workspace project", - "produces": [ + "description": "Find a workspace template", + "consumes": [ "application/json" ], "tags": [ - "workspace toolbox" + "workspace-template" ], - "summary": "Search for files", - "operationId": "FsSearchFiles", + "summary": "Find a workspace template", + "operationId": "FindWorkspaceTemplate", "parameters": [ { "type": "string", - "description": "Workspace ID or Name", - "name": "workspaceId", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Project ID", - "name": "projectId", + "description": "Template name", + "name": "templateName", "in": "path", "required": true - }, - { - "type": "string", - "description": "Path", - "name": "path", - "in": "query", - "required": true - }, - { - "type": "string", - "description": "Pattern", - "name": "pattern", - "in": "query", - "required": true } ], "responses": { "200": { "description": "OK", "schema": { - "$ref": "#/definitions/SearchFilesResponse" + "$ref": "#/definitions/WorkspaceTemplate" } } } - } - }, - "/workspace/{workspaceId}/{projectId}/toolbox/files/upload": { - "post": { - "description": "Upload file inside workspace project", - "produces": [ - "application/json" - ], + }, + "delete": { + "description": "Delete workspace template data", "tags": [ - "workspace toolbox" + "workspace-template" ], - "summary": "Upload file", - "operationId": "FsUploadFile", + "summary": "Delete workspace template data", + "operationId": "DeleteWorkspaceTemplate", "parameters": [ { "type": "string", - "description": "Workspace ID or Name", - "name": "workspaceId", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Project ID", - "name": "projectId", + "description": "Template name", + "name": "templateName", "in": "path", "required": true }, { - "type": "string", - "description": "Path", - "name": "path", - "in": "query", - "required": true - }, - { - "type": "file", - "description": "File", - "name": "file", - "in": "formData", - "required": true + "type": "boolean", + "description": "Force", + "name": "force", + "in": "query" } ], "responses": { - "200": { - "description": "OK" + "204": { + "description": "No Content" } } } }, - "/workspace/{workspaceId}/{projectId}/toolbox/git/add": { - "post": { - "description": "Add files to git commit", - "produces": [ + "/workspace-template/{templateName}/prebuild": { + "get": { + "description": "List prebuilds for workspace template", + "consumes": [ "application/json" ], "tags": [ - "workspace toolbox" + "prebuild" ], - "summary": "Add files", - "operationId": "GitAddFiles", + "summary": "List prebuilds for workspace template", + "operationId": "ListPrebuildsForWorkspaceTemplate", "parameters": [ { "type": "string", - "description": "Workspace ID or Name", - "name": "workspaceId", + "description": "Template name", + "name": "templateName", "in": "path", "required": true - }, + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/PrebuildDTO" + } + } + } + } + }, + "put": { + "description": "Save prebuild", + "consumes": [ + "application/json" + ], + "tags": [ + "prebuild" + ], + "summary": "Save prebuild", + "operationId": "SavePrebuild", + "parameters": [ { "type": "string", - "description": "Project ID", - "name": "projectId", + "description": "Template name", + "name": "templateName", "in": "path", "required": true }, { - "description": "GitAddRequest", - "name": "params", + "description": "Prebuild", + "name": "prebuild", "in": "body", "required": true, "schema": { - "$ref": "#/definitions/GitAddRequest" + "$ref": "#/definitions/CreatePrebuildDTO" } } ], "responses": { - "200": { - "description": "OK" + "201": { + "description": "Created", + "schema": { + "type": "string" + } } } } }, - "/workspace/{workspaceId}/{projectId}/toolbox/git/branches": { + "/workspace-template/{templateName}/prebuild/{prebuildId}": { "get": { - "description": "Get branch list from git repository inside workspace project", - "produces": [ + "description": "Find prebuild", + "consumes": [ "application/json" ], "tags": [ - "workspace toolbox" + "prebuild" ], - "summary": "Get branch list", - "operationId": "GitBranchList", + "summary": "Find prebuild", + "operationId": "FindPrebuild", "parameters": [ { "type": "string", - "description": "Workspace ID or Name", - "name": "workspaceId", + "description": "Workspace template name", + "name": "templateName", "in": "path", "required": true }, { "type": "string", - "description": "Project ID", - "name": "projectId", + "description": "Prebuild ID", + "name": "prebuildId", "in": "path", "required": true - }, - { - "type": "string", - "description": "Path to git repository", - "name": "path", - "in": "query", - "required": true } ], "responses": { "200": { "description": "OK", "schema": { - "$ref": "#/definitions/ListBranchResponse" + "$ref": "#/definitions/PrebuildDTO" } } } }, - "post": { - "description": "Create branch on git repository inside workspace project", - "produces": [ + "delete": { + "description": "Delete prebuild", + "consumes": [ "application/json" ], "tags": [ - "workspace toolbox" + "prebuild" ], - "summary": "Create branch", - "operationId": "GitCreateBranch", + "summary": "Delete prebuild", + "operationId": "DeletePrebuild", "parameters": [ { "type": "string", - "description": "Workspace ID or Name", - "name": "workspaceId", + "description": "Workspace template name", + "name": "templateName", "in": "path", "required": true }, { "type": "string", - "description": "Project ID", - "name": "projectId", + "description": "Prebuild ID", + "name": "prebuildId", "in": "path", "required": true }, { - "description": "GitBranchRequest", - "name": "params", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/GitBranchRequest" - } + "type": "boolean", + "description": "Force", + "name": "force", + "in": "query" } ], "responses": { - "201": { - "description": "Created" + "204": { + "description": "No Content" } } } }, - "/workspace/{workspaceId}/{projectId}/toolbox/git/clone": { - "post": { - "description": "Clone git repository inside workspace project", - "produces": [ - "application/json" - ], + "/workspace-template/{templateName}/set-default": { + "patch": { + "description": "Set workspace template to default", "tags": [ - "workspace toolbox" + "workspace-template" ], - "summary": "Clone git repository", - "operationId": "GitCloneRepository", + "summary": "Set workspace template to default", + "operationId": "SetDefaultWorkspaceTemplate", "parameters": [ { "type": "string", - "description": "Workspace ID or Name", - "name": "workspaceId", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Project ID", - "name": "projectId", + "description": "Template name", + "name": "templateName", "in": "path", "required": true - }, - { - "description": "GitCloneRequest", - "name": "params", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/GitCloneRequest" - } } ], "responses": { @@ -2582,17 +2338,17 @@ const docTemplate = `{ } } }, - "/workspace/{workspaceId}/{projectId}/toolbox/git/commit": { - "post": { - "description": "Commit changes to git repository inside workspace project", + "/workspace/{workspaceId}": { + "get": { + "description": "Find workspace", "produces": [ "application/json" ], "tags": [ - "workspace toolbox" + "workspace" ], - "summary": "Commit changes", - "operationId": "GitCommitChanges", + "summary": "Find workspace", + "operationId": "FindWorkspace", "parameters": [ { "type": "string", @@ -2600,45 +2356,54 @@ const docTemplate = `{ "name": "workspaceId", "in": "path", "required": true - }, + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/WorkspaceDTO" + } + } + } + }, + "delete": { + "description": "Delete workspace", + "tags": [ + "workspace" + ], + "summary": "Delete workspace", + "operationId": "DeleteWorkspace", + "parameters": [ { "type": "string", - "description": "Project ID", - "name": "projectId", + "description": "Workspace ID", + "name": "workspaceId", "in": "path", "required": true }, { - "description": "GitCommitRequest", - "name": "params", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/GitCommitRequest" - } + "type": "boolean", + "description": "Force", + "name": "force", + "in": "query" } ], "responses": { "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/GitCommitResponse" - } + "description": "OK" } } } }, - "/workspace/{workspaceId}/{projectId}/toolbox/git/history": { - "get": { - "description": "Get commit history from git repository inside workspace project", - "produces": [ - "application/json" - ], + "/workspace/{workspaceId}/labels": { + "post": { + "description": "Update workspace labels", "tags": [ - "workspace toolbox" + "workspace" ], - "summary": "Get commit history", - "operationId": "GitCommitHistory", + "summary": "Update workspace labels", + "operationId": "UpdateWorkspaceLabels", "parameters": [ { "type": "string", @@ -2648,66 +2413,51 @@ const docTemplate = `{ "required": true }, { - "type": "string", - "description": "Project ID", - "name": "projectId", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Path to git repository", - "name": "path", - "in": "query", - "required": true + "description": "Labels", + "name": "labels", + "in": "body", + "required": true, + "schema": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } } ], "responses": { "200": { "description": "OK", "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/GitCommitInfo" - } + "$ref": "#/definitions/WorkspaceDTO" } } } } }, - "/workspace/{workspaceId}/{projectId}/toolbox/git/pull": { + "/workspace/{workspaceId}/metadata": { "post": { - "description": "Pull changes from remote to git repository inside workspace project", - "produces": [ - "application/json" - ], + "description": "Update workspace metadata", "tags": [ - "workspace toolbox" + "workspace" ], - "summary": "Pull changes", - "operationId": "GitPullChanges", + "summary": "Update workspace metadata", + "operationId": "UpdateWorkspaceMetadata", "parameters": [ { "type": "string", - "description": "Workspace ID or Name", + "description": "Workspace ID", "name": "workspaceId", "in": "path", "required": true }, { - "type": "string", - "description": "Project ID", - "name": "projectId", - "in": "path", - "required": true - }, - { - "description": "Git pull request", - "name": "params", + "description": "Workspace Metadata", + "name": "workspaceMetadata", "in": "body", "required": true, "schema": { - "$ref": "#/definitions/GitRepoRequest" + "$ref": "#/definitions/UpdateWorkspaceMetadataDTO" } } ], @@ -2718,39 +2468,29 @@ const docTemplate = `{ } } }, - "/workspace/{workspaceId}/{projectId}/toolbox/git/push": { + "/workspace/{workspaceId}/provider-metadata": { "post": { - "description": "Push changes to remote from git repository inside workspace project", - "produces": [ - "application/json" - ], + "description": "Update workspace provider metadata", "tags": [ - "workspace toolbox" + "workspace" ], - "summary": "Push changes", - "operationId": "GitPushChanges", + "summary": "Update workspace provider metadata", + "operationId": "UpdateWorkspaceProviderMetadata", "parameters": [ { "type": "string", - "description": "Workspace ID or Name", + "description": "Workspace ID", "name": "workspaceId", "in": "path", "required": true }, { - "type": "string", - "description": "Project ID", - "name": "projectId", - "in": "path", - "required": true - }, - { - "description": "Git push request", - "name": "params", + "description": "Provider metadata", + "name": "metadata", "in": "body", "required": true, "schema": { - "$ref": "#/definitions/GitRepoRequest" + "$ref": "#/definitions/UpdateWorkspaceProviderMetadataDTO" } } ], @@ -2761,17 +2501,14 @@ const docTemplate = `{ } } }, - "/workspace/{workspaceId}/{projectId}/toolbox/git/status": { - "get": { - "description": "Get status from git repository inside workspace project", - "produces": [ - "application/json" - ], + "/workspace/{workspaceId}/restart": { + "post": { + "description": "Restart workspace", "tags": [ - "workspace toolbox" + "workspace" ], - "summary": "Get git status", - "operationId": "GitGitStatus", + "summary": "Restart workspace", + "operationId": "RestartWorkspace", "parameters": [ { "type": "string", @@ -2779,43 +2516,50 @@ const docTemplate = `{ "name": "workspaceId", "in": "path", "required": true - }, + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/workspace/{workspaceId}/start": { + "post": { + "description": "Start workspace", + "tags": [ + "workspace" + ], + "summary": "Start workspace", + "operationId": "StartWorkspace", + "parameters": [ { "type": "string", - "description": "Project ID", - "name": "projectId", + "description": "Workspace ID or Name", + "name": "workspaceId", "in": "path", "required": true - }, - { - "type": "string", - "description": "Path to git repository", - "name": "path", - "in": "query", - "required": true } ], "responses": { "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/GitStatus" - } + "description": "OK" } } } }, - "/workspace/{workspaceId}/{projectId}/toolbox/lsp/completions": { - "post": { - "description": "The Completion request is sent from the client to the server to compute completion items at a given cursor position.", + "/workspace/{workspaceId}/state": { + "get": { + "description": "Get workspace state", "produces": [ "application/json" ], "tags": [ - "workspace toolbox" + "workspace" ], - "summary": "Get Lsp Completions", - "operationId": "LspCompletions", + "summary": "Get workspace state", + "operationId": "GetWorkspaceState", "parameters": [ { "type": "string", @@ -2823,45 +2567,26 @@ const docTemplate = `{ "name": "workspaceId", "in": "path", "required": true - }, - { - "type": "string", - "description": "Project ID", - "name": "projectId", - "in": "path", - "required": true - }, - { - "description": "LspCompletionParams", - "name": "params", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/LspCompletionParams" - } } ], "responses": { "200": { "description": "OK", "schema": { - "$ref": "#/definitions/CompletionList" + "$ref": "#/definitions/ResourceState" } } } } }, - "/workspace/{workspaceId}/{projectId}/toolbox/lsp/did-close": { + "/workspace/{workspaceId}/stop": { "post": { - "description": "The document close notification is sent from the client to the server when the document got closed in the client.", - "produces": [ - "application/json" - ], + "description": "Stop workspace", "tags": [ - "workspace toolbox" + "workspace" ], - "summary": "Call Lsp DidClose", - "operationId": "LspDidClose", + "summary": "Stop workspace", + "operationId": "StopWorkspace", "parameters": [ { "type": "string", @@ -2869,22 +2594,6 @@ const docTemplate = `{ "name": "workspaceId", "in": "path", "required": true - }, - { - "type": "string", - "description": "Project ID", - "name": "projectId", - "in": "path", - "required": true - }, - { - "description": "LspDocumentRequest", - "name": "params", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/LspDocumentRequest" - } } ], "responses": { @@ -2894,17 +2603,17 @@ const docTemplate = `{ } } }, - "/workspace/{workspaceId}/{projectId}/toolbox/lsp/did-open": { - "post": { - "description": "The document open notification is sent from the client to the server to signal newly opened text documents.", + "/workspace/{workspaceId}/toolbox/files": { + "get": { + "description": "List files inside a workspace", "produces": [ "application/json" ], "tags": [ "workspace toolbox" ], - "summary": "Call Lsp DidOpen", - "operationId": "LspDidOpen", + "summary": "List files", + "operationId": "FsListFiles", "parameters": [ { "type": "string", @@ -2915,39 +2624,33 @@ const docTemplate = `{ }, { "type": "string", - "description": "Project ID", - "name": "projectId", - "in": "path", - "required": true - }, - { - "description": "LspDocumentRequest", - "name": "params", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/LspDocumentRequest" - } + "description": "Path", + "name": "path", + "in": "query" } ], "responses": { "200": { - "description": "OK" + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/FileInfo" + } + } } } - } - }, - "/workspace/{workspaceId}/{projectId}/toolbox/lsp/document-symbols": { - "get": { - "description": "The document symbol request is sent from the client to the server.", + }, + "delete": { + "description": "Delete file inside a workspace", "produces": [ "application/json" ], "tags": [ "workspace toolbox" ], - "summary": "Call Lsp DocumentSymbols", - "operationId": "LspDocumentSymbols", + "summary": "Delete file", + "operationId": "FsDeleteFile", "parameters": [ { "type": "string", @@ -2958,57 +2661,67 @@ const docTemplate = `{ }, { "type": "string", - "description": "Project ID", - "name": "projectId", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Language ID", - "name": "languageId", + "description": "Path", + "name": "path", "in": "query", "required": true - }, + } + ], + "responses": { + "204": { + "description": "No Content" + } + } + } + }, + "/workspace/{workspaceId}/toolbox/files/download": { + "get": { + "description": "Download file from a workspace", + "produces": [ + "application/json" + ], + "tags": [ + "workspace toolbox" + ], + "summary": "Download file", + "operationId": "FsDownloadFile", + "parameters": [ { "type": "string", - "description": "Path to project", - "name": "pathToProject", - "in": "query", + "description": "Workspace ID or Name", + "name": "workspaceId", + "in": "path", "required": true }, { "type": "string", - "description": "Document Uri", - "name": "uri", + "description": "Path", + "name": "path", "in": "query", "required": true } ], "responses": { "200": { - "description": "OK", + "description": "response contains the file", "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/LspSymbol" - } + "type": "file" } } } } }, - "/workspace/{workspaceId}/{projectId}/toolbox/lsp/start": { - "post": { - "description": "Start Lsp server process inside workspace project", + "/workspace/{workspaceId}/toolbox/files/find": { + "get": { + "description": "Search for text/pattern inside a workspace files", "produces": [ "application/json" ], "tags": [ "workspace toolbox" ], - "summary": "Start Lsp server", - "operationId": "LspStart", + "summary": "Search for text/pattern in files", + "operationId": "FsFindInFiles", "parameters": [ { "type": "string", @@ -3019,39 +2732,43 @@ const docTemplate = `{ }, { "type": "string", - "description": "Project ID", - "name": "projectId", - "in": "path", + "description": "Path", + "name": "path", + "in": "query", "required": true }, { - "description": "LspServerRequest", - "name": "params", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/LspServerRequest" - } + "type": "string", + "description": "Pattern", + "name": "pattern", + "in": "query", + "required": true } ], "responses": { "200": { - "description": "OK" + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/Match" + } + } } } } }, - "/workspace/{workspaceId}/{projectId}/toolbox/lsp/stop": { + "/workspace/{workspaceId}/toolbox/files/folder": { "post": { - "description": "Stop Lsp server process inside workspace project", + "description": "Create folder inside a workspace", "produces": [ "application/json" ], "tags": [ "workspace toolbox" ], - "summary": "Stop Lsp server", - "operationId": "LspStop", + "summary": "Create folder", + "operationId": "FsCreateFolder", "parameters": [ { "type": "string", @@ -3062,39 +2779,37 @@ const docTemplate = `{ }, { "type": "string", - "description": "Project ID", - "name": "projectId", - "in": "path", + "description": "Path", + "name": "path", + "in": "query", "required": true }, { - "description": "LspServerRequest", - "name": "params", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/LspServerRequest" - } + "type": "string", + "description": "Mode", + "name": "mode", + "in": "query", + "required": true } ], "responses": { - "200": { - "description": "OK" + "201": { + "description": "Created" } } } }, - "/workspace/{workspaceId}/{projectId}/toolbox/lsp/workspace-symbols": { + "/workspace/{workspaceId}/toolbox/files/info": { "get": { - "description": "The workspace symbol request is sent from the client to the server to list project-wide symbols matching the query string.", + "description": "Get file info inside a workspace", "produces": [ "application/json" ], "tags": [ "workspace toolbox" ], - "summary": "Call Lsp WorkspaceSymbols", - "operationId": "LspWorkspaceSymbols", + "summary": "Get file info", + "operationId": "FsGetFileDetails", "parameters": [ { "type": "string", @@ -3105,29 +2820,8 @@ const docTemplate = `{ }, { "type": "string", - "description": "Project ID", - "name": "projectId", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Language ID", - "name": "languageId", - "in": "query", - "required": true - }, - { - "type": "string", - "description": "Path to project", - "name": "pathToProject", - "in": "query", - "required": true - }, - { - "type": "string", - "description": "Symbol Query", - "name": "query", + "description": "Path", + "name": "path", "in": "query", "required": true } @@ -3136,26 +2830,23 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/LspSymbol" - } + "$ref": "#/definitions/FileInfo" } } } } }, - "/workspace/{workspaceId}/{projectId}/toolbox/process/execute": { + "/workspace/{workspaceId}/toolbox/files/move": { "post": { - "description": "Execute command synchronously inside workspace project", + "description": "Create folder inside a workspace", "produces": [ "application/json" ], "tags": [ "workspace toolbox" ], - "summary": "Execute command", - "operationId": "ProcessExecuteCommand", + "summary": "Create folder", + "operationId": "FsMoveFile", "parameters": [ { "type": "string", @@ -3166,42 +2857,37 @@ const docTemplate = `{ }, { "type": "string", - "description": "Project ID", - "name": "projectId", - "in": "path", + "description": "Source path", + "name": "source", + "in": "query", "required": true }, { - "description": "Execute command request", - "name": "params", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/ExecuteRequest" - } + "type": "string", + "description": "Destination path", + "name": "destination", + "in": "query", + "required": true } ], "responses": { "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/ExecuteResponse" - } + "description": "OK" } } } }, - "/workspace/{workspaceId}/{projectId}/toolbox/process/session": { - "get": { - "description": "List sessions inside workspace project", + "/workspace/{workspaceId}/toolbox/files/permissions": { + "post": { + "description": "Set file owner/group/permissions inside a workspace", "produces": [ "application/json" ], "tags": [ "workspace toolbox" ], - "summary": "List sessions", - "operationId": "ListSessions", + "summary": "Set file owner/group/permissions", + "operationId": "FsSetFilePermissions", "parameters": [ { "type": "string", @@ -3212,34 +2898,48 @@ const docTemplate = `{ }, { "type": "string", - "description": "Project ID", - "name": "projectId", - "in": "path", + "description": "Path", + "name": "path", + "in": "query", "required": true + }, + { + "type": "string", + "description": "Owner", + "name": "owner", + "in": "query" + }, + { + "type": "string", + "description": "Group", + "name": "group", + "in": "query" + }, + { + "type": "string", + "description": "Mode", + "name": "mode", + "in": "query" } ], "responses": { "200": { - "description": "OK", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/Session" - } - } + "description": "OK" } } - }, + } + }, + "/workspace/{workspaceId}/toolbox/files/replace": { "post": { - "description": "Create exec session inside workspace project", + "description": "Repleace text/pattern in mutilple files inside a workspace", "produces": [ "application/json" ], "tags": [ "workspace toolbox" ], - "summary": "Create exec session", - "operationId": "CreateSession", + "summary": "Repleace text/pattern in files", + "operationId": "FsReplaceInFiles", "parameters": [ { "type": "string", @@ -3249,40 +2949,39 @@ const docTemplate = `{ "required": true }, { - "type": "string", - "description": "Project ID", - "name": "projectId", - "in": "path", - "required": true - }, - { - "description": "Create session request", - "name": "params", + "description": "ReplaceParams", + "name": "replace", "in": "body", "required": true, "schema": { - "$ref": "#/definitions/CreateSessionRequest" + "$ref": "#/definitions/ReplaceRequest" } } ], "responses": { - "201": { - "description": "Created" + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/ReplaceResult" + } + } } } } }, - "/workspace/{workspaceId}/{projectId}/toolbox/process/session/{sessionId}": { - "delete": { - "description": "Delete a session inside workspace project", + "/workspace/{workspaceId}/toolbox/files/search": { + "get": { + "description": "Search for files inside a workspace", "produces": [ "application/json" ], "tags": [ "workspace toolbox" ], - "summary": "Delete session", - "operationId": "DeleteSession", + "summary": "Search for files", + "operationId": "FsSearchFiles", "parameters": [ { "type": "string", @@ -3293,34 +2992,40 @@ const docTemplate = `{ }, { "type": "string", - "description": "Project ID", - "name": "projectId", - "in": "path", + "description": "Path", + "name": "path", + "in": "query", "required": true }, { "type": "string", - "description": "Session ID", - "name": "sessionId", - "in": "path", + "description": "Pattern", + "name": "pattern", + "in": "query", "required": true } ], "responses": { - "204": { - "description": "No Content" + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/SearchFilesResponse" + } } } } }, - "/workspace/{workspaceId}/{projectId}/toolbox/process/session/{sessionId}/command/{commandId}/logs": { - "get": { - "description": "Get logs of a command inside a session inside workspace project\nConnect with websocket to get a stream of the logs", + "/workspace/{workspaceId}/toolbox/files/upload": { + "post": { + "description": "Upload file inside a workspace", + "produces": [ + "application/json" + ], "tags": [ "workspace toolbox" ], - "summary": "Get session command logs", - "operationId": "GetSessionCommandLogs", + "summary": "Upload file", + "operationId": "FsUploadFile", "parameters": [ { "type": "string", @@ -3331,16 +3036,809 @@ const docTemplate = `{ }, { "type": "string", - "description": "Project ID", - "name": "projectId", - "in": "path", + "description": "Path", + "name": "path", + "in": "query", "required": true }, { - "type": "string", - "description": "Session ID", - "name": "sessionId", - "in": "path", + "type": "file", + "description": "File", + "name": "file", + "in": "formData", + "required": true + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/workspace/{workspaceId}/toolbox/git/add": { + "post": { + "description": "Add files to git commit", + "produces": [ + "application/json" + ], + "tags": [ + "workspace toolbox" + ], + "summary": "Add files", + "operationId": "GitAddFiles", + "parameters": [ + { + "type": "string", + "description": "Workspace ID or Name", + "name": "workspaceId", + "in": "path", + "required": true + }, + { + "description": "GitAddRequest", + "name": "params", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/GitAddRequest" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/workspace/{workspaceId}/toolbox/git/branches": { + "get": { + "description": "Get branch list from git repository inside a workspace", + "produces": [ + "application/json" + ], + "tags": [ + "workspace toolbox" + ], + "summary": "Get branch list", + "operationId": "GitBranchList", + "parameters": [ + { + "type": "string", + "description": "Workspace ID or Name", + "name": "workspaceId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Path to git repository", + "name": "path", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/ListBranchResponse" + } + } + } + }, + "post": { + "description": "Create branch on git repository inside a workspace", + "produces": [ + "application/json" + ], + "tags": [ + "workspace toolbox" + ], + "summary": "Create branch", + "operationId": "GitCreateBranch", + "parameters": [ + { + "type": "string", + "description": "Workspace ID or Name", + "name": "workspaceId", + "in": "path", + "required": true + }, + { + "description": "GitBranchRequest", + "name": "params", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/GitBranchRequest" + } + } + ], + "responses": { + "201": { + "description": "Created" + } + } + } + }, + "/workspace/{workspaceId}/toolbox/git/clone": { + "post": { + "description": "Clone git repository inside a workspace", + "produces": [ + "application/json" + ], + "tags": [ + "workspace toolbox" + ], + "summary": "Clone git repository", + "operationId": "GitCloneRepository", + "parameters": [ + { + "type": "string", + "description": "Workspace ID or Name", + "name": "workspaceId", + "in": "path", + "required": true + }, + { + "description": "GitCloneRequest", + "name": "params", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/GitCloneRequest" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/workspace/{workspaceId}/toolbox/git/commit": { + "post": { + "description": "Commit changes to git repository inside a workspace", + "produces": [ + "application/json" + ], + "tags": [ + "workspace toolbox" + ], + "summary": "Commit changes", + "operationId": "GitCommitChanges", + "parameters": [ + { + "type": "string", + "description": "Workspace ID or Name", + "name": "workspaceId", + "in": "path", + "required": true + }, + { + "description": "GitCommitRequest", + "name": "params", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/GitCommitRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/GitCommitResponse" + } + } + } + } + }, + "/workspace/{workspaceId}/toolbox/git/history": { + "get": { + "description": "Get commit history from git repository inside a workspace", + "produces": [ + "application/json" + ], + "tags": [ + "workspace toolbox" + ], + "summary": "Get commit history", + "operationId": "GitCommitHistory", + "parameters": [ + { + "type": "string", + "description": "Workspace ID or Name", + "name": "workspaceId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Path to git repository", + "name": "path", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/GitCommitInfo" + } + } + } + } + } + }, + "/workspace/{workspaceId}/toolbox/git/pull": { + "post": { + "description": "Pull changes from remote to git repository inside a workspace", + "produces": [ + "application/json" + ], + "tags": [ + "workspace toolbox" + ], + "summary": "Pull changes", + "operationId": "GitPullChanges", + "parameters": [ + { + "type": "string", + "description": "Workspace ID or Name", + "name": "workspaceId", + "in": "path", + "required": true + }, + { + "description": "Git pull request", + "name": "params", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/GitRepoRequest" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/workspace/{workspaceId}/toolbox/git/push": { + "post": { + "description": "Push changes to remote from git repository inside a workspace", + "produces": [ + "application/json" + ], + "tags": [ + "workspace toolbox" + ], + "summary": "Push changes", + "operationId": "GitPushChanges", + "parameters": [ + { + "type": "string", + "description": "Workspace ID or Name", + "name": "workspaceId", + "in": "path", + "required": true + }, + { + "description": "Git push request", + "name": "params", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/GitRepoRequest" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/workspace/{workspaceId}/toolbox/git/status": { + "get": { + "description": "Get status from git repository inside a workspace", + "produces": [ + "application/json" + ], + "tags": [ + "workspace toolbox" + ], + "summary": "Get git status", + "operationId": "GitGitStatus", + "parameters": [ + { + "type": "string", + "description": "Workspace ID or Name", + "name": "workspaceId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Path to git repository", + "name": "path", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/GitStatus" + } + } + } + } + }, + "/workspace/{workspaceId}/toolbox/lsp/completions": { + "post": { + "description": "The Completion request is sent from the client to the server to compute completion items at a given cursor position.", + "produces": [ + "application/json" + ], + "tags": [ + "workspace toolbox" + ], + "summary": "Get Lsp Completions", + "operationId": "LspCompletions", + "parameters": [ + { + "type": "string", + "description": "Workspace ID or Name", + "name": "workspaceId", + "in": "path", + "required": true + }, + { + "description": "LspCompletionParams", + "name": "params", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/LspCompletionParams" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/CompletionList" + } + } + } + } + }, + "/workspace/{workspaceId}/toolbox/lsp/did-close": { + "post": { + "description": "The document close notification is sent from the client to the server when the document got closed in the client.", + "produces": [ + "application/json" + ], + "tags": [ + "workspace toolbox" + ], + "summary": "Call Lsp DidClose", + "operationId": "LspDidClose", + "parameters": [ + { + "type": "string", + "description": "Workspace ID or Name", + "name": "workspaceId", + "in": "path", + "required": true + }, + { + "description": "LspDocumentRequest", + "name": "params", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/LspDocumentRequest" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/workspace/{workspaceId}/toolbox/lsp/did-open": { + "post": { + "description": "The document open notification is sent from the client to the server to signal newly opened text documents.", + "produces": [ + "application/json" + ], + "tags": [ + "workspace toolbox" + ], + "summary": "Call Lsp DidOpen", + "operationId": "LspDidOpen", + "parameters": [ + { + "type": "string", + "description": "Workspace ID or Name", + "name": "workspaceId", + "in": "path", + "required": true + }, + { + "description": "LspDocumentRequest", + "name": "params", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/LspDocumentRequest" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/workspace/{workspaceId}/toolbox/lsp/document-symbols": { + "get": { + "description": "The document symbol request is sent from the client to the server.", + "produces": [ + "application/json" + ], + "tags": [ + "workspace toolbox" + ], + "summary": "Call Lsp DocumentSymbols", + "operationId": "LspDocumentSymbols", + "parameters": [ + { + "type": "string", + "description": "Workspace ID or Name", + "name": "workspaceId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Language ID", + "name": "languageId", + "in": "query", + "required": true + }, + { + "type": "string", + "description": "Path to project", + "name": "pathToProject", + "in": "query", + "required": true + }, + { + "type": "string", + "description": "Document Uri", + "name": "uri", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/LspSymbol" + } + } + } + } + } + }, + "/workspace/{workspaceId}/toolbox/lsp/start": { + "post": { + "description": "Start Lsp server process inside a workspace", + "produces": [ + "application/json" + ], + "tags": [ + "workspace toolbox" + ], + "summary": "Start Lsp server", + "operationId": "LspStart", + "parameters": [ + { + "type": "string", + "description": "Workspace ID or Name", + "name": "workspaceId", + "in": "path", + "required": true + }, + { + "description": "LspServerRequest", + "name": "params", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/LspServerRequest" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/workspace/{workspaceId}/toolbox/lsp/stop": { + "post": { + "description": "Stop Lsp server process inside a workspace", + "produces": [ + "application/json" + ], + "tags": [ + "workspace toolbox" + ], + "summary": "Stop Lsp server", + "operationId": "LspStop", + "parameters": [ + { + "type": "string", + "description": "Workspace ID or Name", + "name": "workspaceId", + "in": "path", + "required": true + }, + { + "description": "LspServerRequest", + "name": "params", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/LspServerRequest" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/workspace/{workspaceId}/toolbox/lsp/workspace-symbols": { + "get": { + "description": "The workspace symbol request is sent from the client to the server to list project-wide symbols matching the query string.", + "produces": [ + "application/json" + ], + "tags": [ + "workspace toolbox" + ], + "summary": "Call Lsp WorkspaceSymbols", + "operationId": "LspWorkspaceSymbols", + "parameters": [ + { + "type": "string", + "description": "Workspace ID or Name", + "name": "workspaceId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Language ID", + "name": "languageId", + "in": "query", + "required": true + }, + { + "type": "string", + "description": "Path to project", + "name": "pathToProject", + "in": "query", + "required": true + }, + { + "type": "string", + "description": "Symbol Query", + "name": "query", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/LspSymbol" + } + } + } + } + } + }, + "/workspace/{workspaceId}/toolbox/process/execute": { + "post": { + "description": "Execute command synchronously inside a workspace", + "produces": [ + "application/json" + ], + "tags": [ + "workspace toolbox" + ], + "summary": "Execute command", + "operationId": "ProcessExecuteCommand", + "parameters": [ + { + "type": "string", + "description": "Workspace ID or Name", + "name": "workspaceId", + "in": "path", + "required": true + }, + { + "description": "Execute command request", + "name": "params", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/ExecuteRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/ExecuteResponse" + } + } + } + } + }, + "/workspace/{workspaceId}/toolbox/process/session": { + "get": { + "description": "List sessions inside workspace project", + "produces": [ + "application/json" + ], + "tags": [ + "workspace toolbox" + ], + "summary": "List sessions", + "operationId": "ListSessions", + "parameters": [ + { + "type": "string", + "description": "Workspace ID or Name", + "name": "workspaceId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/Session" + } + } + } + } + }, + "post": { + "description": "Create exec session inside workspace project", + "produces": [ + "application/json" + ], + "tags": [ + "workspace toolbox" + ], + "summary": "Create exec session", + "operationId": "CreateSession", + "parameters": [ + { + "type": "string", + "description": "Workspace ID or Name", + "name": "workspaceId", + "in": "path", + "required": true + }, + { + "description": "Create session request", + "name": "params", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/CreateSessionRequest" + } + } + ], + "responses": { + "201": { + "description": "Created" + } + } + } + }, + "/workspace/{workspaceId}/toolbox/process/session/{sessionId}": { + "delete": { + "description": "Delete a session inside workspace project", + "produces": [ + "application/json" + ], + "tags": [ + "workspace toolbox" + ], + "summary": "Delete session", + "operationId": "DeleteSession", + "parameters": [ + { + "type": "string", + "description": "Workspace ID or Name", + "name": "workspaceId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Session ID", + "name": "sessionId", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "No Content" + } + } + } + }, + "/workspace/{workspaceId}/toolbox/process/session/{sessionId}/command/{commandId}/logs": { + "get": { + "description": "Get logs of a command inside a session inside workspace project\nConnect with websocket to get a stream of the logs", + "tags": [ + "workspace toolbox" + ], + "summary": "Get session command logs", + "operationId": "GetSessionCommandLogs", + "parameters": [ + { + "type": "string", + "description": "Workspace ID or Name", + "name": "workspaceId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Session ID", + "name": "sessionId", + "in": "path", "required": true }, { @@ -3361,7 +3859,7 @@ const docTemplate = `{ } } }, - "/workspace/{workspaceId}/{projectId}/toolbox/process/session/{sessionId}/exec": { + "/workspace/{workspaceId}/toolbox/process/session/{sessionId}/exec": { "post": { "description": "Execute command inside a session inside workspace project", "produces": [ @@ -3380,13 +3878,6 @@ const docTemplate = `{ "in": "path", "required": true }, - { - "type": "string", - "description": "Project ID", - "name": "projectId", - "in": "path", - "required": true - }, { "type": "string", "description": "Session ID", @@ -3414,17 +3905,17 @@ const docTemplate = `{ } } }, - "/workspace/{workspaceId}/{projectId}/toolbox/project-dir": { + "/workspace/{workspaceId}/toolbox/workspace-dir": { "get": { - "description": "Get project directory", + "description": "Get workspace directory", "produces": [ "application/json" ], "tags": [ "workspace toolbox" ], - "summary": "Get project dir", - "operationId": "GetProjectDir", + "summary": "Get workspace dir", + "operationId": "GetWorkspaceDir", "parameters": [ { "type": "string", @@ -3432,20 +3923,13 @@ const docTemplate = `{ "name": "workspaceId", "in": "path", "required": true - }, - { - "type": "string", - "description": "Project ID", - "name": "projectId", - "in": "path", - "required": true } ], "responses": { "200": { "description": "OK", "schema": { - "$ref": "#/definitions/ProjectDirResponse" + "$ref": "#/definitions/WorkspaceDirResponse" } } } @@ -3453,34 +3937,43 @@ const docTemplate = `{ } }, "definitions": { - "ApiKey": { + "ApiKeyViewDTO": { "type": "object", "required": [ - "keyHash", + "current", "name", "type" ], "properties": { - "keyHash": { - "type": "string" + "current": { + "type": "boolean" }, "name": { - "description": "Project or client name", "type": "string" }, "type": { - "$ref": "#/definitions/apikey.ApiKeyType" + "$ref": "#/definitions/models.ApiKeyType" + } + } + }, + "BuildConfig": { + "type": "object", + "properties": { + "cachedBuild": { + "$ref": "#/definitions/CachedBuild" + }, + "devcontainer": { + "$ref": "#/definitions/DevcontainerConfig" } } }, - "Build": { + "BuildDTO": { "type": "object", "required": [ "containerConfig", "createdAt", "envVars", "id", - "prebuildId", "repository", "state", "updatedAt" @@ -3507,6 +4000,12 @@ const docTemplate = `{ "image": { "type": "string" }, + "lastJob": { + "$ref": "#/definitions/Job" + }, + "lastJobId": { + "type": "string" + }, "prebuildId": { "type": "string" }, @@ -3514,7 +4013,7 @@ const docTemplate = `{ "$ref": "#/definitions/GitRepository" }, "state": { - "$ref": "#/definitions/build.BuildState" + "$ref": "#/definitions/ResourceState" }, "updatedAt": { "type": "string" @@ -3524,17 +4023,6 @@ const docTemplate = `{ } } }, - "BuildConfig": { - "type": "object", - "properties": { - "cachedBuild": { - "$ref": "#/definitions/CachedBuild" - }, - "devcontainer": { - "$ref": "#/definitions/DevcontainerConfig" - } - } - }, "CachedBuild": { "type": "object", "required": [ @@ -3677,7 +4165,7 @@ const docTemplate = `{ "required": [ "branch", "envVars", - "projectConfigName" + "workspaceTemplateName" ], "properties": { "branch": { @@ -3692,7 +4180,7 @@ const docTemplate = `{ "prebuildId": { "type": "string" }, - "projectConfigName": { + "workspaceTemplateName": { "type": "string" } } @@ -3723,46 +4211,101 @@ const docTemplate = `{ } } }, - "CreateProjectConfigDTO": { + "CreateRunnerDTO": { "type": "object", "required": [ - "envVars", - "name", - "repositoryUrl" + "id", + "name" ], "properties": { - "buildConfig": { - "$ref": "#/definitions/BuildConfig" - }, - "envVars": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "id": { + "type": "string" }, - "gitProviderConfigId": { + "name": { + "type": "string" + } + } + }, + "CreateRunnerResultDTO": { + "type": "object", + "required": [ + "apiKey", + "id", + "name" + ], + "properties": { + "apiKey": { "type": "string" }, - "image": { + "id": { "type": "string" }, + "metadata": { + "$ref": "#/definitions/RunnerMetadata" + }, + "name": { + "type": "string" + } + } + }, + "CreateSessionRequest": { + "type": "object", + "required": [ + "sessionId" + ], + "properties": { + "sessionId": { + "type": "string" + } + } + }, + "CreateTargetConfigDTO": { + "type": "object", + "required": [ + "name", + "options", + "providerInfo" + ], + "properties": { "name": { "type": "string" }, - "repositoryUrl": { + "options": { "type": "string" }, - "user": { + "providerInfo": { + "$ref": "#/definitions/ProviderInfo" + } + } + }, + "CreateTargetDTO": { + "type": "object", + "required": [ + "id", + "name", + "targetConfigId" + ], + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "targetConfigId": { "type": "string" } } }, - "CreateProjectDTO": { + "CreateWorkspaceDTO": { "type": "object", "required": [ "envVars", + "id", + "labels", "name", - "source" + "source", + "targetId" ], "properties": { "buildConfig": { @@ -3777,83 +4320,73 @@ const docTemplate = `{ "gitProviderConfigId": { "type": "string" }, + "id": { + "type": "string" + }, "image": { "type": "string" }, + "labels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, "name": { "type": "string" }, "source": { - "$ref": "#/definitions/CreateProjectSourceDTO" + "$ref": "#/definitions/CreateWorkspaceSourceDTO" }, - "user": { - "type": "string" - } - } - }, - "CreateProjectSourceDTO": { - "type": "object", - "required": [ - "repository" - ], - "properties": { - "repository": { - "$ref": "#/definitions/GitRepository" - } - } - }, - "CreateProviderTargetDTO": { - "type": "object", - "required": [ - "name", - "options", - "providerInfo" - ], - "properties": { - "name": { + "targetId": { "type": "string" }, - "options": { + "user": { "type": "string" - }, - "providerInfo": { - "$ref": "#/definitions/provider.ProviderInfo" } } }, - "CreateSessionRequest": { + "CreateWorkspaceSourceDTO": { "type": "object", "required": [ - "sessionId" + "repository" ], "properties": { - "sessionId": { - "type": "string" + "repository": { + "$ref": "#/definitions/GitRepository" } } }, - "CreateWorkspaceDTO": { + "CreateWorkspaceTemplateDTO": { "type": "object", "required": [ - "id", + "envVars", "name", - "projects", - "target" + "repositoryUrl" ], "properties": { - "id": { + "buildConfig": { + "$ref": "#/definitions/BuildConfig" + }, + "envVars": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "gitProviderConfigId": { + "type": "string" + }, + "image": { "type": "string" }, "name": { "type": "string" }, - "projects": { - "type": "array", - "items": { - "$ref": "#/definitions/CreateProjectDTO" - } + "repositoryUrl": { + "type": "string" }, - "target": { + "user": { "type": "string" } } @@ -3869,6 +4402,21 @@ const docTemplate = `{ } } }, + "EnvironmentVariable": { + "type": "object", + "required": [ + "key", + "value" + ], + "properties": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + } + } + }, "ExecuteRequest": { "type": "object", "required": [ @@ -4349,24 +4897,66 @@ const docTemplate = `{ } } }, - "InstallProviderRequest": { + "Job": { "type": "object", "required": [ - "downloadUrls", - "name" + "action", + "createdAt", + "id", + "resourceId", + "resourceType", + "state", + "updatedAt" ], "properties": { - "downloadUrls": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "action": { + "$ref": "#/definitions/models.JobAction" }, - "name": { + "createdAt": { + "type": "string" + }, + "error": { + "type": "string" + }, + "id": { + "type": "string" + }, + "metadata": { + "description": "JSON encoded metadata", + "type": "string" + }, + "resourceId": { + "type": "string" + }, + "resourceType": { + "$ref": "#/definitions/ResourceType" + }, + "runnerId": { + "type": "string" + }, + "state": { + "$ref": "#/definitions/JobState" + }, + "updatedAt": { "type": "string" } } }, + "JobState": { + "type": "string", + "enum": [ + "pending", + "running", + "error", + "success" + ], + "x-enum-varnames": [ + "JobStatePending", + "JobStateRunning", + "JobStateError", + "JobStateSuccess" + ] + }, "ListBranchResponse": { "type": "object", "required": [ @@ -4583,7 +5173,6 @@ const docTemplate = `{ "type": "object", "required": [ "branch", - "commitInterval", "id", "retention", "triggerFiles" @@ -4614,8 +5203,8 @@ const docTemplate = `{ "required": [ "branch", "id", - "projectConfigName", - "retention" + "retention", + "workspaceTemplateName" ], "properties": { "branch": { @@ -4627,9 +5216,6 @@ const docTemplate = `{ "id": { "type": "string" }, - "projectConfigName": { - "type": "string" - }, "retention": { "type": "integer" }, @@ -4638,260 +5224,195 @@ const docTemplate = `{ "items": { "type": "string" } + }, + "workspaceTemplateName": { + "type": "string" } } }, - "ProfileData": { - "type": "object", - "required": [ - "envVars" - ], - "properties": { - "envVars": { - "type": "object", - "additionalProperties": { - "type": "string" - } - } - } - }, - "Project": { + "ProviderDTO": { "type": "object", "required": [ - "envVars", - "image", + "latest", "name", - "repository", - "target", - "user", - "workspaceId" + "version" ], "properties": { - "buildConfig": { - "$ref": "#/definitions/BuildConfig" - }, - "envVars": { - "type": "object", - "additionalProperties": { - "type": "string" - } - }, - "gitProviderConfigId": { + "label": { "type": "string" }, - "image": { - "type": "string" + "latest": { + "type": "boolean" }, "name": { "type": "string" }, - "repository": { - "$ref": "#/definitions/GitRepository" - }, - "state": { - "$ref": "#/definitions/ProjectState" - }, - "target": { - "type": "string" - }, - "user": { - "type": "string" - }, - "workspaceId": { + "version": { "type": "string" } } }, - "ProjectConfig": { + "ProviderInfo": { "type": "object", "required": [ - "default", - "envVars", - "image", "name", - "repositoryUrl", - "user" + "runnerId", + "runnerName", + "targetConfigManifest", + "version" ], "properties": { - "buildConfig": { - "$ref": "#/definitions/BuildConfig" - }, - "default": { + "agentlessTarget": { "type": "boolean" }, - "envVars": { - "type": "object", - "additionalProperties": { - "type": "string" - } - }, - "gitProviderConfigId": { - "type": "string" - }, - "image": { + "label": { "type": "string" }, "name": { "type": "string" }, - "prebuilds": { - "type": "array", - "items": { - "$ref": "#/definitions/PrebuildConfig" - } - }, - "repositoryUrl": { + "runnerId": { "type": "string" }, - "user": { + "runnerName": { "type": "string" - } - } - }, - "ProjectDirResponse": { - "type": "object", - "properties": { - "dir": { + }, + "targetConfigManifest": { + "$ref": "#/definitions/TargetConfigManifest" + }, + "version": { "type": "string" } } }, - "ProjectInfo": { + "ReplaceRequest": { "type": "object", "required": [ - "created", - "isRunning", - "name", - "workspaceId" + "files", + "newValue", + "pattern" ], "properties": { - "created": { - "type": "string" - }, - "isRunning": { - "type": "boolean" - }, - "name": { - "type": "string" + "files": { + "type": "array", + "items": { + "type": "string" + } }, - "providerMetadata": { + "newValue": { "type": "string" }, - "workspaceId": { + "pattern": { "type": "string" } } }, - "ProjectState": { + "ReplaceResult": { "type": "object", - "required": [ - "updatedAt", - "uptime" - ], "properties": { - "gitStatus": { - "$ref": "#/definitions/GitStatus" + "error": { + "type": "string" }, - "updatedAt": { + "file": { "type": "string" }, - "uptime": { - "type": "integer" + "success": { + "type": "boolean" } } }, - "Provider": { + "RepositoryUrl": { "type": "object", "required": [ - "name", - "version" + "url" ], "properties": { - "label": { - "type": "string" - }, - "name": { - "type": "string" - }, - "version": { + "url": { "type": "string" } } }, - "ProviderTarget": { + "ResourceState": { "type": "object", "required": [ - "isDefault", "name", - "options", - "providerInfo" + "updatedAt" ], "properties": { - "isDefault": { - "type": "boolean" + "error": { + "type": "string" }, "name": { - "type": "string" + "$ref": "#/definitions/models.ResourceStateName" }, - "options": { - "description": "JSON encoded map of options", + "updatedAt": { "type": "string" - }, - "providerInfo": { - "$ref": "#/definitions/provider.ProviderInfo" } } }, - "ProviderTargetManifest": { - "type": "object", - "additionalProperties": { - "$ref": "#/definitions/provider.ProviderTargetProperty" - } - }, - "ReplaceRequest": { - "type": "object", - "required": [ - "files", - "newValue", - "pattern" + "ResourceType": { + "type": "string", + "enum": [ + "workspace", + "target", + "build", + "runner" ], - "properties": { - "files": { - "type": "array", - "items": { - "type": "string" - } - }, - "newValue": { - "type": "string" - }, - "pattern": { - "type": "string" - } - } + "x-enum-varnames": [ + "ResourceTypeWorkspace", + "ResourceTypeTarget", + "ResourceTypeBuild", + "ResourceTypeRunner" + ] }, - "ReplaceResult": { + "RunnerDTO": { "type": "object", + "required": [ + "id", + "name", + "state" + ], "properties": { - "error": { + "id": { "type": "string" }, - "file": { + "metadata": { + "$ref": "#/definitions/RunnerMetadata" + }, + "name": { "type": "string" }, - "success": { - "type": "boolean" + "state": { + "$ref": "#/definitions/ResourceState" } } }, - "RepositoryUrl": { + "RunnerMetadata": { "type": "object", "required": [ - "url" + "providers", + "runnerId", + "updatedAt", + "uptime" ], "properties": { - "url": { + "providers": { + "type": "array", + "items": { + "$ref": "#/definitions/ProviderInfo" + } + }, + "runnerId": { + "type": "string" + }, + "runningJobs": { + "type": "integer" + }, + "updatedAt": { "type": "string" + }, + "uptime": { + "type": "integer" } } }, @@ -4935,14 +5456,13 @@ const docTemplate = `{ "binariesPath", "builderImage", "builderRegistryServer", - "defaultProjectImage", - "defaultProjectUser", + "defaultWorkspaceImage", + "defaultWorkspaceUser", "headscalePort", "id", "localBuilderRegistryImage", "localBuilderRegistryPort", "logFile", - "providersDir", "registryUrl", "serverDownloadUrl" ], @@ -4962,10 +5482,10 @@ const docTemplate = `{ "builderRegistryServer": { "type": "string" }, - "defaultProjectImage": { + "defaultWorkspaceImage": { "type": "string" }, - "defaultProjectUser": { + "defaultWorkspaceUser": { "type": "string" }, "frps": { @@ -4983,12 +5503,12 @@ const docTemplate = `{ "localBuilderRegistryPort": { "type": "integer" }, + "localRunnerDisabled": { + "type": "boolean" + }, "logFile": { "$ref": "#/definitions/LogFileConfig" }, - "providersDir": { - "type": "string" - }, "registryUrl": { "type": "string" }, @@ -5079,7 +5599,298 @@ const docTemplate = `{ } } }, - "SetProjectState": { + "SigningMethod": { + "type": "string", + "enum": [ + "ssh", + "gpg" + ], + "x-enum-varnames": [ + "SigningMethodSSH", + "SigningMethodGPG" + ] + }, + "Status": { + "type": "string", + "enum": [ + "Unmodified", + "Untracked", + "Modified", + "Added", + "Deleted", + "Renamed", + "Copied", + "Updated but unmerged" + ], + "x-enum-varnames": [ + "Unmodified", + "Untracked", + "Modified", + "Added", + "Deleted", + "Renamed", + "Copied", + "UpdatedButUnmerged" + ] + }, + "Target": { + "type": "object", + "required": [ + "default", + "envVars", + "id", + "name", + "targetConfig", + "targetConfigId", + "workspaces" + ], + "properties": { + "default": { + "type": "boolean" + }, + "envVars": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "id": { + "type": "string" + }, + "lastJob": { + "$ref": "#/definitions/Job" + }, + "lastJobId": { + "type": "string" + }, + "metadata": { + "$ref": "#/definitions/TargetMetadata" + }, + "name": { + "type": "string" + }, + "providerMetadata": { + "type": "string" + }, + "targetConfig": { + "$ref": "#/definitions/TargetConfig" + }, + "targetConfigId": { + "type": "string" + }, + "workspaces": { + "type": "array", + "items": { + "$ref": "#/definitions/Workspace" + } + } + } + }, + "TargetConfig": { + "type": "object", + "required": [ + "deleted", + "id", + "name", + "options", + "providerInfo" + ], + "properties": { + "deleted": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "options": { + "description": "JSON encoded map of options", + "type": "string" + }, + "providerInfo": { + "$ref": "#/definitions/ProviderInfo" + } + } + }, + "TargetConfigManifest": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/TargetConfigProperty" + } + }, + "TargetConfigProperty": { + "type": "object", + "properties": { + "defaultValue": { + "description": "DefaultValue is converted into the appropriate type based on the Type\nIf the property is a FilePath, the DefaultValue is a path to a directory", + "type": "string" + }, + "description": { + "description": "Brief description of the property", + "type": "string" + }, + "disabledPredicate": { + "description": "A regex string matched with the name of the target config to determine if the property should be disabled\nIf the regex matches the target config name, the property will be disabled\nE.g. \"^local$\" will disable the property for the local target", + "type": "string" + }, + "inputMasked": { + "type": "boolean" + }, + "options": { + "description": "Options is only used if the Type is TargetConfigPropertyTypeOption", + "type": "array", + "items": { + "type": "string" + } + }, + "suggestions": { + "description": "Suggestions is an optional list of auto-complete values to assist the user while filling the field", + "type": "array", + "items": { + "type": "string" + } + }, + "type": { + "$ref": "#/definitions/models.TargetConfigPropertyType" + } + } + }, + "TargetDTO": { + "type": "object", + "required": [ + "default", + "envVars", + "id", + "name", + "state", + "targetConfig", + "targetConfigId", + "workspaces" + ], + "properties": { + "default": { + "type": "boolean" + }, + "envVars": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "id": { + "type": "string" + }, + "lastJob": { + "$ref": "#/definitions/Job" + }, + "lastJobId": { + "type": "string" + }, + "metadata": { + "$ref": "#/definitions/TargetMetadata" + }, + "name": { + "type": "string" + }, + "providerMetadata": { + "type": "string" + }, + "state": { + "$ref": "#/definitions/ResourceState" + }, + "targetConfig": { + "$ref": "#/definitions/TargetConfig" + }, + "targetConfigId": { + "type": "string" + }, + "workspaces": { + "type": "array", + "items": { + "$ref": "#/definitions/Workspace" + } + } + } + }, + "TargetMetadata": { + "type": "object", + "required": [ + "targetId", + "updatedAt", + "uptime" + ], + "properties": { + "targetId": { + "type": "string" + }, + "updatedAt": { + "type": "string" + }, + "uptime": { + "type": "integer" + } + } + }, + "UpdateJobState": { + "type": "object", + "required": [ + "state" + ], + "properties": { + "errorMessage": { + "type": "string" + }, + "state": { + "$ref": "#/definitions/JobState" + } + } + }, + "UpdateRunnerMetadataDTO": { + "type": "object", + "required": [ + "providers", + "uptime" + ], + "properties": { + "providers": { + "type": "array", + "items": { + "$ref": "#/definitions/ProviderInfo" + } + }, + "runningJobs": { + "type": "integer" + }, + "uptime": { + "type": "integer" + } + } + }, + "UpdateTargetMetadataDTO": { + "type": "object", + "required": [ + "uptime" + ], + "properties": { + "uptime": { + "type": "integer" + } + } + }, + "UpdateTargetProviderMetadataDTO": { + "type": "object", + "required": [ + "metadata" + ], + "properties": { + "metadata": { + "type": "string" + } + } + }, + "UpdateWorkspaceMetadataDTO": { "type": "object", "required": [ "uptime" @@ -5093,62 +5904,84 @@ const docTemplate = `{ } } }, - "SigningMethod": { - "type": "string", - "enum": [ - "ssh", - "gpg" - ], - "x-enum-varnames": [ - "SigningMethodSSH", - "SigningMethodGPG" - ] - }, - "Status": { - "type": "string", - "enum": [ - "Unmodified", - "Untracked", - "Modified", - "Added", - "Deleted", - "Renamed", - "Copied", - "Updated but unmerged" + "UpdateWorkspaceProviderMetadataDTO": { + "type": "object", + "required": [ + "metadata" ], - "x-enum-varnames": [ - "Unmodified", - "Untracked", - "Modified", - "Added", - "Deleted", - "Renamed", - "Copied", - "UpdatedButUnmerged" - ] + "properties": { + "metadata": { + "type": "string" + } + } }, "Workspace": { "type": "object", "required": [ + "apiKey", + "envVars", "id", + "image", + "labels", "name", - "projects", - "target" + "repository", + "target", + "targetId", + "user" ], "properties": { + "apiKey": { + "type": "string" + }, + "buildConfig": { + "$ref": "#/definitions/BuildConfig" + }, + "envVars": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "gitProviderConfigId": { + "type": "string" + }, "id": { "type": "string" }, - "name": { + "image": { "type": "string" }, - "projects": { - "type": "array", - "items": { - "$ref": "#/definitions/Project" + "labels": { + "type": "object", + "additionalProperties": { + "type": "string" } }, + "lastJob": { + "$ref": "#/definitions/Job" + }, + "lastJobId": { + "type": "string" + }, + "metadata": { + "$ref": "#/definitions/WorkspaceMetadata" + }, + "name": { + "type": "string" + }, + "providerMetadata": { + "type": "string" + }, + "repository": { + "$ref": "#/definitions/GitRepository" + }, "target": { + "$ref": "#/definitions/Target" + }, + "targetId": { + "type": "string" + }, + "user": { "type": "string" } } @@ -5156,145 +5989,249 @@ const docTemplate = `{ "WorkspaceDTO": { "type": "object", "required": [ + "apiKey", + "envVars", "id", + "image", + "labels", "name", - "projects", - "target" + "repository", + "state", + "target", + "targetId", + "user" ], "properties": { + "apiKey": { + "type": "string" + }, + "buildConfig": { + "$ref": "#/definitions/BuildConfig" + }, + "envVars": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "gitProviderConfigId": { + "type": "string" + }, "id": { "type": "string" }, - "info": { - "$ref": "#/definitions/WorkspaceInfo" + "image": { + "type": "string" + }, + "labels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "lastJob": { + "$ref": "#/definitions/Job" + }, + "lastJobId": { + "type": "string" + }, + "metadata": { + "$ref": "#/definitions/WorkspaceMetadata" }, "name": { "type": "string" }, - "projects": { - "type": "array", - "items": { - "$ref": "#/definitions/Project" - } + "providerMetadata": { + "type": "string" + }, + "repository": { + "$ref": "#/definitions/GitRepository" + }, + "state": { + "$ref": "#/definitions/ResourceState" }, "target": { + "$ref": "#/definitions/Target" + }, + "targetId": { + "type": "string" + }, + "user": { + "type": "string" + } + } + }, + "WorkspaceDirResponse": { + "type": "object", + "properties": { + "dir": { + "type": "string" + } + } + }, + "WorkspaceMetadata": { + "type": "object", + "required": [ + "updatedAt", + "uptime", + "workspaceId" + ], + "properties": { + "gitStatus": { + "$ref": "#/definitions/GitStatus" + }, + "updatedAt": { + "type": "string" + }, + "uptime": { + "type": "integer" + }, + "workspaceId": { "type": "string" } } }, - "WorkspaceInfo": { + "WorkspaceTemplate": { "type": "object", "required": [ + "default", + "envVars", + "image", + "labels", "name", - "projects" + "repositoryUrl", + "user" ], "properties": { + "buildConfig": { + "$ref": "#/definitions/BuildConfig" + }, + "default": { + "type": "boolean" + }, + "envVars": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "gitProviderConfigId": { + "type": "string" + }, + "image": { + "type": "string" + }, + "labels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, "name": { "type": "string" }, - "projects": { + "prebuilds": { "type": "array", "items": { - "$ref": "#/definitions/ProjectInfo" + "$ref": "#/definitions/PrebuildConfig" } }, - "providerMetadata": { + "repositoryUrl": { + "type": "string" + }, + "user": { "type": "string" } } }, - "apikey.ApiKeyType": { + "models.ApiKeyType": { "type": "string", "enum": [ "client", - "project", - "workspace" + "workspace", + "target", + "runner" ], "x-enum-varnames": [ "ApiKeyTypeClient", - "ApiKeyTypeProject", - "ApiKeyTypeWorkspace" + "ApiKeyTypeWorkspace", + "ApiKeyTypeTarget", + "ApiKeyTypeRunner" ] }, - "build.BuildState": { + "models.JobAction": { "type": "string", "enum": [ + "create", + "start", + "stop", + "restart", + "delete", + "force-delete", + "run", + "install-provider", + "uninstall-provider", + "update-provider" + ], + "x-enum-varnames": [ + "JobActionCreate", + "JobActionStart", + "JobActionStop", + "JobActionRestart", + "JobActionDelete", + "JobActionForceDelete", + "JobActionRun", + "JobActionInstallProvider", + "JobActionUninstallProvider", + "JobActionUpdateProvider" + ] + }, + "models.ResourceStateName": { + "type": "string", + "enum": [ + "undefined", "pending-run", "running", + "run-successful", + "pending-create", + "creating", + "pending-start", + "starting", + "started", + "pending-stop", + "stopping", + "stopped", + "pending-restart", "error", - "success", - "published", + "unresponsive", "pending-delete", "pending-forced-delete", - "deleting" + "deleting", + "deleted" ], "x-enum-varnames": [ - "BuildStatePendingRun", - "BuildStateRunning", - "BuildStateError", - "BuildStateSuccess", - "BuildStatePublished", - "BuildStatePendingDelete", - "BuildStatePendingForcedDelete", - "BuildStateDeleting" + "ResourceStateNameUndefined", + "ResourceStateNamePendingRun", + "ResourceStateNameRunning", + "ResourceStateNameRunSuccessful", + "ResourceStateNamePendingCreate", + "ResourceStateNameCreating", + "ResourceStateNamePendingStart", + "ResourceStateNameStarting", + "ResourceStateNameStarted", + "ResourceStateNamePendingStop", + "ResourceStateNameStopping", + "ResourceStateNameStopped", + "ResourceStateNamePendingRestart", + "ResourceStateNameError", + "ResourceStateNameUnresponsive", + "ResourceStateNamePendingDelete", + "ResourceStateNamePendingForcedDelete", + "ResourceStateNameDeleting", + "ResourceStateNameDeleted" ] }, - "provider.ProviderInfo": { - "type": "object", - "required": [ - "name", - "version" - ], - "properties": { - "label": { - "type": "string" - }, - "name": { - "type": "string" - }, - "version": { - "type": "string" - } - } - }, - "provider.ProviderTargetProperty": { - "type": "object", - "properties": { - "defaultValue": { - "description": "DefaultValue is converted into the appropriate type based on the Type\nIf the property is a FilePath, the DefaultValue is a path to a directory", - "type": "string" - }, - "description": { - "description": "Brief description of the property", - "type": "string" - }, - "disabledPredicate": { - "description": "A regex string matched with the name of the target to determine if the property should be disabled\nIf the regex matches the target name, the property will be disabled\nE.g. \"^local$\" will disable the property for the local target", - "type": "string" - }, - "inputMasked": { - "type": "boolean" - }, - "options": { - "description": "Options is only used if the Type is ProviderTargetPropertyTypeOption", - "type": "array", - "items": { - "type": "string" - } - }, - "suggestions": { - "description": "Suggestions is an optional list of auto-complete values to assist the user while filling the field", - "type": "array", - "items": { - "type": "string" - } - }, - "type": { - "$ref": "#/definitions/provider.ProviderTargetPropertyType" - } - } - }, - "provider.ProviderTargetPropertyType": { + "models.TargetConfigPropertyType": { "type": "string", "enum": [ "string", @@ -5305,12 +6242,12 @@ const docTemplate = `{ "file-path" ], "x-enum-varnames": [ - "ProviderTargetPropertyTypeString", - "ProviderTargetPropertyTypeOption", - "ProviderTargetPropertyTypeBoolean", - "ProviderTargetPropertyTypeInt", - "ProviderTargetPropertyTypeFloat", - "ProviderTargetPropertyTypeFilePath" + "TargetConfigPropertyTypeString", + "TargetConfigPropertyTypeOption", + "TargetConfigPropertyTypeBoolean", + "TargetConfigPropertyTypeInt", + "TargetConfigPropertyTypeFloat", + "TargetConfigPropertyTypeFilePath" ] } }, diff --git a/pkg/api/docs/swagger.json b/pkg/api/docs/swagger.json index 868ccdda88..166f8e3093 100644 --- a/pkg/api/docs/swagger.json +++ b/pkg/api/docs/swagger.json @@ -29,7 +29,7 @@ "schema": { "type": "array", "items": { - "$ref": "#/definitions/ApiKey" + "$ref": "#/definitions/ApiKeyViewDTO" } } } @@ -38,15 +38,15 @@ }, "/apikey/{apiKeyName}": { "post": { - "description": "Generate an API key", + "description": "Create an API key", "produces": [ "text/plain" ], "tags": [ "apiKey" ], - "summary": "Generate an API key", - "operationId": "GenerateApiKey", + "summary": "Create an API key", + "operationId": "CreateApiKey", "parameters": [ { "type": "string", @@ -66,12 +66,12 @@ } }, "delete": { - "description": "Revoke API key", + "description": "Delete API key", "tags": [ "apiKey" ], - "summary": "Revoke API key", - "operationId": "RevokeApiKey", + "summary": "Delete API key", + "operationId": "DeleteApiKey", "parameters": [ { "type": "string", @@ -105,7 +105,7 @@ "schema": { "type": "array", "items": { - "$ref": "#/definitions/Build" + "$ref": "#/definitions/BuildDTO" } } } @@ -193,17 +193,50 @@ } } }, + "/build/successful/{repoUrl}": { + "get": { + "description": "List successful builds for Git repository", + "produces": [ + "application/json" + ], + "tags": [ + "build" + ], + "summary": "List successful builds for Git repository", + "operationId": "ListSuccessfulBuilds", + "parameters": [ + { + "type": "string", + "description": "Repository URL", + "name": "repoUrl", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/BuildDTO" + } + } + } + } + } + }, "/build/{buildId}": { "get": { - "description": "Get build data", + "description": "Find build", "consumes": [ "application/json" ], "tags": [ "build" ], - "summary": "Get build data", - "operationId": "GetBuild", + "summary": "Find build", + "operationId": "FindBuild", "parameters": [ { "type": "string", @@ -217,7 +250,7 @@ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/Build" + "$ref": "#/definitions/BuildDTO" } } } @@ -251,81 +284,83 @@ } } }, - "/container-registry": { + "/container-registry/{server}": { "get": { - "description": "List container registries", + "description": "Find container registry", "produces": [ "application/json" ], "tags": [ - "container-registry" + "container registry" + ], + "summary": "Find container registry", + "operationId": "FindContainerRegistry", + "parameters": [ + { + "type": "string", + "description": "Container registry server", + "name": "server", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Workspace ID or Name", + "name": "workspaceId", + "in": "query" + } ], - "summary": "List container registries", - "operationId": "ListContainerRegistries", "responses": { "200": { "description": "OK", "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/ContainerRegistry" - } + "$ref": "#/definitions/ContainerRegistry" } } } } }, - "/container-registry/{server}": { + "/env": { "get": { - "description": "Get container registry credentials", + "description": "List environment variables", "produces": [ "application/json" ], "tags": [ - "container-registry" - ], - "summary": "Get container registry credentials", - "operationId": "GetContainerRegistry", - "parameters": [ - { - "type": "string", - "description": "Container Registry server name", - "name": "server", - "in": "path", - "required": true - } + "envVar" ], + "summary": "List environment variables", + "operationId": "ListEnvironmentVariables", "responses": { "200": { "description": "OK", "schema": { - "$ref": "#/definitions/ContainerRegistry" + "type": "array", + "items": { + "$ref": "#/definitions/EnvironmentVariable" + } } } } }, "put": { - "description": "Set container registry credentials", + "description": "Save environment variable", + "consumes": [ + "application/json" + ], "tags": [ - "container-registry" + "envVar" ], - "summary": "Set container registry credentials", - "operationId": "SetContainerRegistry", + "summary": "Save environment variable", + "operationId": "SaveEnvironmentVariable", "parameters": [ { - "type": "string", - "description": "Container Registry server name", - "name": "server", - "in": "path", - "required": true - }, - { - "description": "Container Registry credentials to set", - "name": "containerRegistry", + "description": "Environment Variable", + "name": "environmentVariable", "in": "body", "required": true, "schema": { - "$ref": "#/definitions/ContainerRegistry" + "$ref": "#/definitions/EnvironmentVariable" } } ], @@ -334,19 +369,21 @@ "description": "Created" } } - }, + } + }, + "/env/{key}": { "delete": { - "description": "Remove a container registry credentials", + "description": "Delete environment variable", "tags": [ - "container-registry" + "envVar" ], - "summary": "Remove a container registry credentials", - "operationId": "RemoveContainerRegistry", + "summary": "Delete environment variable", + "operationId": "DeleteEnvironmentVariable", "parameters": [ { "type": "string", - "description": "Container Registry server name", - "name": "server", + "description": "Environment Variable Key", + "name": "key", "in": "path", "required": true } @@ -382,15 +419,15 @@ } }, "put": { - "description": "Set Git provider", + "description": "Save Git provider", "produces": [ "application/json" ], "tags": [ "gitProvider" ], - "summary": "Set Git provider", - "operationId": "SetGitProvider", + "summary": "Save Git provider", + "operationId": "SaveGitProvider", "parameters": [ { "description": "Git provider", @@ -508,15 +545,15 @@ }, "/gitprovider/id-for-url/{url}": { "get": { - "description": "Get Git provider ID", + "description": "Find Git provider ID", "produces": [ "text/plain" ], "tags": [ "gitProvider" ], - "summary": "Get Git provider ID", - "operationId": "GetGitProviderIdForUrl", + "summary": "Find Git provider ID", + "operationId": "FindGitProviderIdForUrl", "parameters": [ { "type": "string", @@ -538,15 +575,15 @@ }, "/gitprovider/{gitProviderId}": { "get": { - "description": "Get Git provider", + "description": "Find Git provider", "produces": [ "text/plain" ], "tags": [ "gitProvider" ], - "summary": "Get Git provider", - "operationId": "GetGitProvider", + "summary": "Find Git provider", + "operationId": "FindGitProvider", "parameters": [ { "type": "string", @@ -566,15 +603,15 @@ } }, "delete": { - "description": "Remove Git provider", + "description": "Delete Git provider", "produces": [ "application/json" ], "tags": [ "gitProvider" ], - "summary": "Remove Git provider", - "operationId": "RemoveGitProvider", + "summary": "Delete Git provider", + "operationId": "DeleteGitProvider", "parameters": [ { "type": "string", @@ -857,214 +894,190 @@ } } }, - "/profile": { + "/job": { "get": { - "description": "Get profile data", - "consumes": [ - "application/json" - ], - "tags": [ - "profile" - ], - "summary": "Get profile data", - "operationId": "GetProfileData", - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/ProfileData" - } - } - } - }, - "put": { - "description": "Set profile data", - "consumes": [ + "description": "List jobs", + "produces": [ "application/json" ], "tags": [ - "profile" + "job" ], - "summary": "Set profile data", - "operationId": "SetProfileData", + "summary": "List jobs", + "operationId": "ListJobs", "parameters": [ { - "description": "Profile data", - "name": "profileData", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/ProfileData" - } - } - ], - "responses": { - "201": { - "description": "Created" + "type": "array", + "items": { + "type": "string" + }, + "collectionFormat": "multi", + "description": "Job States", + "name": "states", + "in": "query" + }, + { + "type": "array", + "items": { + "type": "string" + }, + "collectionFormat": "multi", + "description": "Job Actions", + "name": "actions", + "in": "query" + }, + { + "type": "string", + "description": "Resource ID", + "name": "resourceId", + "in": "query" + }, + { + "type": "string", + "description": "Resource Type", + "name": "resourceType", + "in": "query" } - } - }, - "delete": { - "description": "Delete profile data", - "tags": [ - "profile" ], - "summary": "Delete profile data", - "operationId": "DeleteProfileData", "responses": { - "204": { - "description": "No Content" + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/Job" + } + } } } } }, - "/project-config": { + "/runner": { "get": { - "description": "List project configs", + "description": "List runners", "produces": [ "application/json" ], "tags": [ - "project-config" + "runner" ], - "summary": "List project configs", - "operationId": "ListProjectConfigs", + "summary": "List runners", + "operationId": "ListRunners", "responses": { "200": { "description": "OK", "schema": { "type": "array", "items": { - "$ref": "#/definitions/ProjectConfig" + "$ref": "#/definitions/RunnerDTO" } } } } }, - "put": { - "description": "Set project config data", - "consumes": [ + "post": { + "description": "Create a runner", + "produces": [ "application/json" ], "tags": [ - "project-config" + "runner" ], - "summary": "Set project config data", - "operationId": "SetProjectConfig", + "summary": "Create a runner", + "operationId": "CreateRunner", "parameters": [ { - "description": "Project config", - "name": "projectConfig", + "description": "Runner", + "name": "runner", "in": "body", "required": true, "schema": { - "$ref": "#/definitions/CreateProjectConfigDTO" + "$ref": "#/definitions/CreateRunnerDTO" } } ], "responses": { - "201": { - "description": "Created" + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/CreateRunnerResultDTO" + } } } } }, - "/project-config/default/{gitUrl}": { + "/runner/provider": { "get": { - "description": "Get project configs by git url", + "description": "List providers", "produces": [ "application/json" ], "tags": [ - "project-config" + "provider" ], - "summary": "Get project configs by git url", - "operationId": "GetDefaultProjectConfig", + "summary": "List providers", + "operationId": "ListProviders", "parameters": [ { "type": "string", - "description": "Git URL", - "name": "gitUrl", - "in": "path", - "required": true + "description": "Runner ID", + "name": "runnerId", + "in": "query" } ], "responses": { "200": { "description": "OK", "schema": { - "$ref": "#/definitions/ProjectConfig" + "type": "array", + "items": { + "$ref": "#/definitions/ProviderInfo" + } } } } } }, - "/project-config/prebuild": { + "/runner/provider/for-install": { "get": { - "description": "List prebuilds", - "consumes": [ + "description": "List providers available for installation", + "produces": [ "application/json" ], "tags": [ - "prebuild" + "provider" ], - "summary": "List prebuilds", - "operationId": "ListPrebuilds", + "summary": "List providers available for installation", + "operationId": "ListProvidersForInstall", "responses": { "200": { "description": "OK", "schema": { "type": "array", "items": { - "$ref": "#/definitions/PrebuildDTO" + "$ref": "#/definitions/ProviderDTO" } } } } } }, - "/project-config/prebuild/process-git-event": { - "post": { - "description": "ProcessGitEvent", - "tags": [ - "prebuild" - ], - "summary": "ProcessGitEvent", - "operationId": "ProcessGitEvent", - "parameters": [ - { - "description": "Webhook event", - "name": "workspace", - "in": "body", - "required": true, - "schema": { - "type": "object" - } - } - ], - "responses": { - "200": { - "description": "OK" - } - } - } - }, - "/project-config/{configName}": { + "/runner/{runnerId}": { "get": { - "description": "Get project config data", - "consumes": [ + "description": "Find a runner", + "produces": [ "application/json" ], "tags": [ - "project-config" + "runner" ], - "summary": "Get project config data", - "operationId": "GetProjectConfig", + "summary": "Find a runner", + "operationId": "FindRunner", "parameters": [ { "type": "string", - "description": "Config name", - "name": "configName", + "description": "Runner ID", + "name": "runnerId", "in": "path", "required": true } @@ -1073,56 +1086,50 @@ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/ProjectConfig" + "$ref": "#/definitions/RunnerDTO" } } } }, "delete": { - "description": "Delete project config data", + "description": "Delete runner", "tags": [ - "project-config" + "runner" ], - "summary": "Delete project config data", - "operationId": "DeleteProjectConfig", + "summary": "Delete runner", + "operationId": "DeleteRunner", "parameters": [ { "type": "string", - "description": "Config name", - "name": "configName", + "description": "Runner ID", + "name": "runnerId", "in": "path", "required": true - }, - { - "type": "boolean", - "description": "Force", - "name": "force", - "in": "query" } ], "responses": { - "204": { - "description": "No Content" + "200": { + "description": "OK" } } } }, - "/project-config/{configName}/prebuild": { + "/runner/{runnerId}/jobs": { "get": { - "description": "List prebuilds for project config", - "consumes": [ + "description": "List runner jobs", + "produces": [ "application/json" ], "tags": [ - "prebuild" + "runner" ], - "summary": "List prebuilds for project config", - "operationId": "ListPrebuildsForProjectConfig", + "summary": "List runner jobs", + "operationId": "ListRunnerJobs", "parameters": [ { "type": "string", - "description": "Config name", - "name": "configName", + "description": "Runner ID", + "name": "runnerId", "in": "path", "required": true } @@ -1133,193 +1140,150 @@ "schema": { "type": "array", "items": { - "$ref": "#/definitions/PrebuildDTO" + "$ref": "#/definitions/Job" } } } } - }, - "put": { - "description": "Set prebuild", - "consumes": [ + } + }, + "/runner/{runnerId}/jobs/{jobId}/state": { + "post": { + "description": "Update job state", + "produces": [ "application/json" ], "tags": [ - "prebuild" + "runner" ], - "summary": "Set prebuild", - "operationId": "SetPrebuild", + "summary": "Update job state", + "operationId": "UpdateJobState", "parameters": [ { "type": "string", - "description": "Config name", - "name": "configName", + "description": "Runner ID", + "name": "runnerId", "in": "path", "required": true }, { - "description": "Prebuild", - "name": "prebuild", + "type": "string", + "description": "Job ID", + "name": "jobId", + "in": "path", + "required": true + }, + { + "description": "Update job state", + "name": "updateJobState", "in": "body", "required": true, "schema": { - "$ref": "#/definitions/CreatePrebuildDTO" + "$ref": "#/definitions/UpdateJobState" } } ], "responses": { - "201": { - "description": "Created", - "schema": { - "type": "string" - } + "200": { + "description": "OK" } } } }, - "/project-config/{configName}/prebuild/{prebuildId}": { - "get": { - "description": "Get prebuild", - "consumes": [ - "application/json" - ], + "/runner/{runnerId}/metadata": { + "post": { + "description": "Update runner metadata", "tags": [ - "prebuild" + "runner" ], - "summary": "Get prebuild", - "operationId": "GetPrebuild", + "summary": "Update runner metadata", + "operationId": "UpdateRunnerMetadata", "parameters": [ { "type": "string", - "description": "Project config name", - "name": "configName", + "description": "Runner ID", + "name": "runnerId", "in": "path", "required": true }, { - "type": "string", - "description": "Prebuild ID", - "name": "prebuildId", - "in": "path", - "required": true + "description": "Runner Metadata", + "name": "runnerMetadata", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/UpdateRunnerMetadataDTO" + } } ], "responses": { "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/PrebuildDTO" - } + "description": "OK" } } - }, - "delete": { - "description": "Delete prebuild", - "consumes": [ + } + }, + "/runner/{runnerId}/provider": { + "get": { + "description": "Get runner providers", + "produces": [ "application/json" ], "tags": [ - "prebuild" + "provider" ], - "summary": "Delete prebuild", - "operationId": "DeletePrebuild", + "summary": "Get runner providers", + "operationId": "GetRunnerProviders", "parameters": [ { "type": "string", - "description": "Project config name", - "name": "configName", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Prebuild ID", - "name": "prebuildId", - "in": "path", - "required": true - }, - { - "type": "boolean", - "description": "Force", - "name": "force", - "in": "query" - } - ], - "responses": { - "204": { - "description": "No Content" - } - } - } - }, - "/project-config/{configName}/set-default": { - "patch": { - "description": "Set project config to default", - "tags": [ - "project-config" - ], - "summary": "Set project config to default", - "operationId": "SetDefaultProjectConfig", - "parameters": [ - { - "type": "string", - "description": "Config name", - "name": "configName", + "description": "Runner ID", + "name": "runnerId", "in": "path", "required": true } ], - "responses": { - "200": { - "description": "OK" - } - } - } - }, - "/provider": { - "get": { - "description": "List providers", - "produces": [ - "application/json" - ], - "tags": [ - "provider" - ], - "summary": "List providers", - "operationId": "ListProviders", "responses": { "200": { "description": "OK", "schema": { "type": "array", "items": { - "$ref": "#/definitions/Provider" + "$ref": "#/definitions/ProviderInfo" } } } } } }, - "/provider/install": { + "/runner/{runnerId}/provider/{providerName}/install": { "post": { - "description": "Install a provider", - "consumes": [ - "application/json" - ], + "description": "Install provider", "tags": [ "provider" ], - "summary": "Install a provider", + "summary": "Install provider", "operationId": "InstallProvider", "parameters": [ { - "description": "Provider to install", - "name": "provider", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/InstallProviderRequest" - } + "type": "string", + "description": "Runner ID", + "name": "runnerId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Provider name", + "name": "providerName", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Provider version - defaults to 'latest'", + "name": "providerVersion", + "in": "query" } ], "responses": { @@ -1329,51 +1293,65 @@ } } }, - "/provider/{provider}/target-manifest": { - "get": { - "description": "Get provider target manifest", + "/runner/{runnerId}/provider/{providerName}/uninstall": { + "post": { + "description": "Uninstall provider", "tags": [ "provider" ], - "summary": "Get provider target manifest", - "operationId": "GetTargetManifest", + "summary": "Uninstall provider", + "operationId": "UninstallProvider", "parameters": [ + { + "type": "string", + "description": "Runner ID", + "name": "runnerId", + "in": "path", + "required": true + }, { "type": "string", "description": "Provider name", - "name": "provider", + "name": "providerName", "in": "path", "required": true } ], "responses": { "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/ProviderTargetManifest" - } + "description": "OK" } } } }, - "/provider/{provider}/uninstall": { + "/runner/{runnerId}/provider/{providerName}/update": { "post": { - "description": "Uninstall a provider", - "consumes": [ - "application/json" - ], + "description": "Update provider", "tags": [ "provider" ], - "summary": "Uninstall a provider", - "operationId": "UninstallProvider", + "summary": "Update provider", + "operationId": "UpdateProvider", "parameters": [ { "type": "string", - "description": "Provider to uninstall", - "name": "provider", + "description": "Runner ID", + "name": "runnerId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Provider name", + "name": "providerName", "in": "path", "required": true + }, + { + "type": "string", + "description": "Provider version - defaults to 'latest'", + "name": "providerVersion", + "in": "query" } ], "responses": { @@ -1427,8 +1405,8 @@ } } }, - "post": { - "description": "Set the server configuration", + "put": { + "description": "Save the server configuration", "consumes": [ "application/json" ], @@ -1438,8 +1416,8 @@ "tags": [ "server" ], - "summary": "Set the server configuration", - "operationId": "SetConfig", + "summary": "Save the server configuration", + "operationId": "SaveConfig", "parameters": [ { "description": "Server configuration", @@ -1463,14 +1441,14 @@ }, "/server/logs": { "get": { - "description": "List server log files", + "description": "Get server log files", "produces": [ "application/json" ], "tags": [ "server" ], - "summary": "List server log files", + "summary": "Get server log files", "operationId": "GetServerLogFiles", "responses": { "200": { @@ -1487,15 +1465,15 @@ }, "/server/network-key": { "post": { - "description": "Generate a new authentication key", + "description": "Create a new authentication key", "produces": [ "application/json" ], "tags": [ "server" ], - "summary": "Generate a new authentication key", - "operationId": "GenerateNetworkKey", + "summary": "Create a new authentication key", + "operationId": "CreateNetworkKey", "responses": { "200": { "description": "OK", @@ -1517,107 +1495,73 @@ ], "summary": "List targets", "operationId": "ListTargets", + "parameters": [ + { + "type": "boolean", + "description": "Show target config options", + "name": "showOptions", + "in": "query" + } + ], "responses": { "200": { "description": "OK", "schema": { "type": "array", "items": { - "$ref": "#/definitions/ProviderTarget" + "$ref": "#/definitions/TargetDTO" } } } } }, - "put": { - "description": "Set a target", + "post": { + "description": "Create a target", + "produces": [ + "application/json" + ], "tags": [ "target" ], - "summary": "Set a target", - "operationId": "SetTarget", + "summary": "Create a target", + "operationId": "CreateTarget", "parameters": [ { - "description": "Target to set", + "description": "Create target", "name": "target", "in": "body", "required": true, "schema": { - "$ref": "#/definitions/CreateProviderTargetDTO" + "$ref": "#/definitions/CreateTargetDTO" } } ], - "responses": { - "201": { - "description": "Created" - } - } - } - }, - "/target/{target}": { - "delete": { - "description": "Remove a target", - "tags": [ - "target" - ], - "summary": "Remove a target", - "operationId": "RemoveTarget", - "parameters": [ - { - "type": "string", - "description": "Target name", - "name": "target", - "in": "path", - "required": true - } - ], - "responses": { - "204": { - "description": "No Content" - } - } - } - }, - "/target/{target}/set-default": { - "patch": { - "description": "Set target to default", - "tags": [ - "target" - ], - "summary": "Set target to default", - "operationId": "SetDefaultTarget", - "parameters": [ - { - "type": "string", - "description": "Target name", - "name": "target", - "in": "path", - "required": true - } - ], "responses": { "200": { - "description": "OK" + "description": "OK", + "schema": { + "$ref": "#/definitions/Target" + } } } } }, - "/workspace": { + "/target-config": { "get": { - "description": "List workspaces", + "description": "List target configs", "produces": [ "application/json" ], "tags": [ - "workspace" + "target-config" ], - "summary": "List workspaces", - "operationId": "ListWorkspaces", + "summary": "List target configs", + "operationId": "ListTargetConfigs", "parameters": [ { "type": "boolean", - "description": "Verbose", - "name": "verbose", + "description": "Show target config options", + "name": "showOptions", "in": "query" } ], @@ -1627,66 +1571,93 @@ "schema": { "type": "array", "items": { - "$ref": "#/definitions/WorkspaceDTO" + "$ref": "#/definitions/TargetConfig" } } } } }, "post": { - "description": "Create a workspace", - "produces": [ - "application/json" - ], + "description": "Create a target config", "tags": [ - "workspace" + "target-config" ], - "summary": "Create a workspace", - "operationId": "CreateWorkspace", + "summary": "Create a target config", + "operationId": "CreateTargetConfig", "parameters": [ { - "description": "Create workspace", - "name": "workspace", + "description": "Target config to create", + "name": "targetConfig", "in": "body", "required": true, "schema": { - "$ref": "#/definitions/CreateWorkspaceDTO" + "$ref": "#/definitions/CreateTargetConfigDTO" } + }, + { + "type": "boolean", + "description": "Show target config options", + "name": "showOptions", + "in": "query" } ], "responses": { "200": { "description": "OK", "schema": { - "$ref": "#/definitions/Workspace" + "$ref": "#/definitions/TargetConfig" } } } } }, - "/workspace/{workspaceId}": { + "/target-config/{configId}": { + "delete": { + "description": "Delete a target config", + "tags": [ + "target-config" + ], + "summary": "Delete a target config", + "operationId": "DeleteTargetConfig", + "parameters": [ + { + "type": "string", + "description": "Target Config Id", + "name": "configId", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "No Content" + } + } + } + }, + "/target/{targetId}": { "get": { - "description": "Get workspace info", + "description": "Find target", "produces": [ "application/json" ], "tags": [ - "workspace" + "target" ], - "summary": "Get workspace info", - "operationId": "GetWorkspace", + "summary": "Find target", + "operationId": "FindTarget", "parameters": [ { "type": "string", - "description": "Workspace ID or Name", - "name": "workspaceId", + "description": "Target ID or Name", + "name": "targetId", "in": "path", "required": true }, { "type": "boolean", - "description": "Verbose", - "name": "verbose", + "description": "Show target config options", + "name": "showOptions", "in": "query" } ], @@ -1694,23 +1665,23 @@ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/WorkspaceDTO" + "$ref": "#/definitions/TargetDTO" } } } }, "delete": { - "description": "Remove workspace", + "description": "Delete target", "tags": [ - "workspace" + "target" ], - "summary": "Remove workspace", - "operationId": "RemoveWorkspace", + "summary": "Delete target", + "operationId": "DeleteTarget", "parameters": [ { "type": "string", - "description": "Workspace ID", - "name": "workspaceId", + "description": "Target ID", + "name": "targetId", "in": "path", "required": true }, @@ -1728,19 +1699,19 @@ } } }, - "/workspace/{workspaceId}/start": { + "/target/{targetId}/handle-successful-creation": { "post": { - "description": "Start workspace", + "description": "Handles successful creation of the target", "tags": [ - "workspace" + "target" ], - "summary": "Start workspace", - "operationId": "StartWorkspace", + "summary": "Handles successful creation of the target", + "operationId": "HandleSuccessfulCreation", "parameters": [ { "type": "string", - "description": "Workspace ID or Name", - "name": "workspaceId", + "description": "Target ID or name", + "name": "targetId", "in": "path", "required": true } @@ -1752,21 +1723,30 @@ } } }, - "/workspace/{workspaceId}/stop": { + "/target/{targetId}/metadata": { "post": { - "description": "Stop workspace", + "description": "Update target metadata", "tags": [ - "workspace" + "target" ], - "summary": "Stop workspace", - "operationId": "StopWorkspace", + "summary": "Update target metadata", + "operationId": "UpdateTargetMetadata", "parameters": [ { "type": "string", - "description": "Workspace ID or Name", - "name": "workspaceId", + "description": "Target ID", + "name": "targetId", "in": "path", "required": true + }, + { + "description": "Target Metadata", + "name": "targetMetadata", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/UpdateTargetMetadataDTO" + } } ], "responses": { @@ -1776,28 +1756,30 @@ } } }, - "/workspace/{workspaceId}/{projectId}/start": { + "/target/{targetId}/provider-metadata": { "post": { - "description": "Start project", + "description": "Update target provider metadata", "tags": [ - "workspace" + "target" ], - "summary": "Start project", - "operationId": "StartProject", + "summary": "Update target provider metadata", + "operationId": "UpdateTargetProviderMetadata", "parameters": [ { "type": "string", - "description": "Workspace ID or Name", - "name": "workspaceId", + "description": "Target ID", + "name": "targetId", "in": "path", "required": true }, { - "type": "string", - "description": "Project ID", - "name": "projectId", - "in": "path", - "required": true + "description": "Provider metadata", + "name": "metadata", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/UpdateTargetProviderMetadataDTO" + } } ], "responses": { @@ -1807,37 +1789,21 @@ } } }, - "/workspace/{workspaceId}/{projectId}/state": { + "/target/{targetId}/restart": { "post": { - "description": "Set project state", + "description": "Restart target", "tags": [ - "workspace" + "target" ], - "summary": "Set project state", - "operationId": "SetProjectState", + "summary": "Restart target", + "operationId": "RestartTarget", "parameters": [ { "type": "string", - "description": "Workspace ID or Name", - "name": "workspaceId", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Project ID", - "name": "projectId", + "description": "Target ID or Name", + "name": "targetId", "in": "path", "required": true - }, - { - "description": "Set State", - "name": "setState", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/SetProjectState" - } } ], "responses": { @@ -1847,26 +1813,19 @@ } } }, - "/workspace/{workspaceId}/{projectId}/stop": { - "post": { - "description": "Stop project", + "/target/{targetId}/set-default": { + "patch": { + "description": "Set target to be used by default", "tags": [ - "workspace" + "target" ], - "summary": "Stop project", - "operationId": "StopProject", + "summary": "Set target to be used by default", + "operationId": "SetDefaultTarget", "parameters": [ { "type": "string", - "description": "Workspace ID or Name", - "name": "workspaceId", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Project ID", - "name": "projectId", + "description": "Target ID or name", + "name": "targetId", "in": "path", "required": true } @@ -1878,174 +1837,101 @@ } } }, - "/workspace/{workspaceId}/{projectId}/toolbox/files": { - "get": { - "description": "List files inside workspace project", - "produces": [ - "application/json" - ], + "/target/{targetId}/start": { + "post": { + "description": "Start target", "tags": [ - "workspace toolbox" + "target" ], - "summary": "List files", - "operationId": "FsListFiles", + "summary": "Start target", + "operationId": "StartTarget", "parameters": [ { "type": "string", - "description": "Workspace ID or Name", - "name": "workspaceId", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Project ID", - "name": "projectId", + "description": "Target ID or Name", + "name": "targetId", "in": "path", "required": true - }, - { - "type": "string", - "description": "Path", - "name": "path", - "in": "query" } ], "responses": { "200": { - "description": "OK", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/FileInfo" - } - } + "description": "OK" } } - }, - "delete": { - "description": "Delete file inside workspace project", + } + }, + "/target/{targetId}/state": { + "get": { + "description": "Get target state", "produces": [ "application/json" ], "tags": [ - "workspace toolbox" + "target" ], - "summary": "Delete file", - "operationId": "FsDeleteFile", + "summary": "Get target state", + "operationId": "GetTargetState", "parameters": [ { "type": "string", - "description": "Workspace ID or Name", - "name": "workspaceId", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Project ID", - "name": "projectId", + "description": "Target ID or Name", + "name": "targetId", "in": "path", "required": true - }, - { - "type": "string", - "description": "Path", - "name": "path", - "in": "query", - "required": true } ], "responses": { - "204": { - "description": "No Content" + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/ResourceState" + } } } } }, - "/workspace/{workspaceId}/{projectId}/toolbox/files/download": { - "get": { - "description": "Download file from workspace project", - "produces": [ - "application/json" - ], + "/target/{targetId}/stop": { + "post": { + "description": "Stop target", "tags": [ - "workspace toolbox" + "target" ], - "summary": "Download file", - "operationId": "FsDownloadFile", + "summary": "Stop target", + "operationId": "StopTarget", "parameters": [ { "type": "string", - "description": "Workspace ID or Name", - "name": "workspaceId", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Project ID", - "name": "projectId", + "description": "Target ID or Name", + "name": "targetId", "in": "path", "required": true - }, - { - "type": "string", - "description": "Path", - "name": "path", - "in": "query", - "required": true } ], "responses": { "200": { - "description": "response contains the file", - "schema": { - "type": "file" - } + "description": "OK" } } } }, - "/workspace/{workspaceId}/{projectId}/toolbox/files/find": { + "/workspace": { "get": { - "description": "Search for text/pattern inside workspace project files", + "description": "List workspaces", "produces": [ "application/json" ], "tags": [ - "workspace toolbox" + "workspace" ], - "summary": "Search for text/pattern in files", - "operationId": "FsFindInFiles", + "summary": "List workspaces", + "operationId": "ListWorkspaces", "parameters": [ { "type": "string", - "description": "Workspace ID or Name", - "name": "workspaceId", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Project ID", - "name": "projectId", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Path", - "name": "path", - "in": "query", - "required": true - }, - { - "type": "string", - "description": "Pattern", - "name": "pattern", - "in": "query", - "required": true + "description": "JSON encoded labels", + "name": "labels", + "in": "query" } ], "responses": { @@ -2054,522 +1940,392 @@ "schema": { "type": "array", "items": { - "$ref": "#/definitions/Match" + "$ref": "#/definitions/WorkspaceDTO" } } } } - } - }, - "/workspace/{workspaceId}/{projectId}/toolbox/files/folder": { + }, "post": { - "description": "Create folder inside workspace project", + "description": "Create a workspace", "produces": [ "application/json" ], "tags": [ - "workspace toolbox" + "workspace" ], - "summary": "Create folder", - "operationId": "FsCreateFolder", + "summary": "Create a workspace", + "operationId": "CreateWorkspace", "parameters": [ { - "type": "string", - "description": "Workspace ID or Name", - "name": "workspaceId", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Project ID", - "name": "projectId", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Path", - "name": "path", - "in": "query", - "required": true - }, - { - "type": "string", - "description": "Mode", - "name": "mode", - "in": "query", - "required": true + "description": "Create workspace", + "name": "workspace", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/CreateWorkspaceDTO" + } } ], "responses": { - "201": { - "description": "Created" + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/WorkspaceDTO" + } } } } }, - "/workspace/{workspaceId}/{projectId}/toolbox/files/info": { + "/workspace-template": { "get": { - "description": "Get file info inside workspace project", + "description": "List workspace templates", "produces": [ "application/json" ], "tags": [ - "workspace toolbox" - ], - "summary": "Get file info", - "operationId": "FsGetFileDetails", - "parameters": [ - { - "type": "string", - "description": "Workspace ID or Name", - "name": "workspaceId", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Project ID", - "name": "projectId", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Path", - "name": "path", - "in": "query", - "required": true - } + "workspace-template" ], + "summary": "List workspace templates", + "operationId": "ListWorkspaceTemplates", "responses": { "200": { "description": "OK", "schema": { - "$ref": "#/definitions/FileInfo" + "type": "array", + "items": { + "$ref": "#/definitions/WorkspaceTemplate" + } + } + } + } + }, + "put": { + "description": "Set workspace template data", + "consumes": [ + "application/json" + ], + "tags": [ + "workspace-template" + ], + "summary": "Set workspace template data", + "operationId": "SaveWorkspaceTemplate", + "parameters": [ + { + "description": "Workspace template", + "name": "workspaceTemplate", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/CreateWorkspaceTemplateDTO" } } + ], + "responses": { + "201": { + "description": "Created" + } } } }, - "/workspace/{workspaceId}/{projectId}/toolbox/files/move": { - "post": { - "description": "Create folder inside workspace project", + "/workspace-template/default/{gitUrl}": { + "get": { + "description": "Get default workspace templates by git url", "produces": [ "application/json" ], "tags": [ - "workspace toolbox" + "workspace-template" ], - "summary": "Create folder", - "operationId": "FsMoveFile", + "summary": "Get default workspace templates by git url", + "operationId": "GetDefaultWorkspaceTemplate", "parameters": [ { "type": "string", - "description": "Workspace ID or Name", - "name": "workspaceId", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Project ID", - "name": "projectId", + "description": "Git URL", + "name": "gitUrl", "in": "path", "required": true - }, - { - "type": "string", - "description": "Source path", - "name": "source", - "in": "query", - "required": true - }, - { - "type": "string", - "description": "Destination path", - "name": "destination", - "in": "query", - "required": true } ], "responses": { "200": { - "description": "OK" + "description": "OK", + "schema": { + "$ref": "#/definitions/WorkspaceTemplate" + } } } } }, - "/workspace/{workspaceId}/{projectId}/toolbox/files/permissions": { - "post": { - "description": "Set file owner/group/permissions inside workspace project", - "produces": [ + "/workspace-template/prebuild": { + "get": { + "description": "List prebuilds", + "consumes": [ "application/json" ], "tags": [ - "workspace toolbox" - ], - "summary": "Set file owner/group/permissions", - "operationId": "FsSetFilePermissions", - "parameters": [ - { - "type": "string", - "description": "Workspace ID or Name", - "name": "workspaceId", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Project ID", - "name": "projectId", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Path", - "name": "path", - "in": "query", - "required": true - }, - { - "type": "string", - "description": "Owner", - "name": "owner", - "in": "query" - }, - { - "type": "string", - "description": "Group", - "name": "group", - "in": "query" - }, - { - "type": "string", - "description": "Mode", - "name": "mode", - "in": "query" - } + "prebuild" ], + "summary": "List prebuilds", + "operationId": "ListPrebuilds", "responses": { "200": { - "description": "OK" + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/PrebuildDTO" + } + } } } } }, - "/workspace/{workspaceId}/{projectId}/toolbox/files/replace": { + "/workspace-template/prebuild/process-git-event": { "post": { - "description": "Repleace text/pattern in mutilple files inside workspace project", - "produces": [ - "application/json" - ], + "description": "ProcessGitEvent", "tags": [ - "workspace toolbox" + "prebuild" ], - "summary": "Repleace text/pattern in files", - "operationId": "FsReplaceInFiles", + "summary": "ProcessGitEvent", + "operationId": "ProcessGitEvent", "parameters": [ { - "type": "string", - "description": "Workspace ID or Name", - "name": "workspaceId", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Project ID", - "name": "projectId", - "in": "path", - "required": true - }, - { - "description": "ReplaceParams", - "name": "replace", + "description": "Webhook event", + "name": "body", "in": "body", "required": true, "schema": { - "$ref": "#/definitions/ReplaceRequest" + "type": "object" } } ], "responses": { "200": { - "description": "OK", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/ReplaceResult" - } - } + "description": "OK" } } } }, - "/workspace/{workspaceId}/{projectId}/toolbox/files/search": { + "/workspace-template/{templateName}": { "get": { - "description": "Search for files inside workspace project", - "produces": [ + "description": "Find a workspace template", + "consumes": [ "application/json" ], "tags": [ - "workspace toolbox" + "workspace-template" ], - "summary": "Search for files", - "operationId": "FsSearchFiles", + "summary": "Find a workspace template", + "operationId": "FindWorkspaceTemplate", "parameters": [ { "type": "string", - "description": "Workspace ID or Name", - "name": "workspaceId", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Project ID", - "name": "projectId", + "description": "Template name", + "name": "templateName", "in": "path", "required": true - }, - { - "type": "string", - "description": "Path", - "name": "path", - "in": "query", - "required": true - }, - { - "type": "string", - "description": "Pattern", - "name": "pattern", - "in": "query", - "required": true } ], "responses": { "200": { "description": "OK", "schema": { - "$ref": "#/definitions/SearchFilesResponse" + "$ref": "#/definitions/WorkspaceTemplate" } } } - } - }, - "/workspace/{workspaceId}/{projectId}/toolbox/files/upload": { - "post": { - "description": "Upload file inside workspace project", - "produces": [ - "application/json" - ], + }, + "delete": { + "description": "Delete workspace template data", "tags": [ - "workspace toolbox" + "workspace-template" ], - "summary": "Upload file", - "operationId": "FsUploadFile", + "summary": "Delete workspace template data", + "operationId": "DeleteWorkspaceTemplate", "parameters": [ { "type": "string", - "description": "Workspace ID or Name", - "name": "workspaceId", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Project ID", - "name": "projectId", + "description": "Template name", + "name": "templateName", "in": "path", "required": true }, { - "type": "string", - "description": "Path", - "name": "path", - "in": "query", - "required": true - }, - { - "type": "file", - "description": "File", - "name": "file", - "in": "formData", - "required": true + "type": "boolean", + "description": "Force", + "name": "force", + "in": "query" } ], "responses": { - "200": { - "description": "OK" + "204": { + "description": "No Content" } } } }, - "/workspace/{workspaceId}/{projectId}/toolbox/git/add": { - "post": { - "description": "Add files to git commit", - "produces": [ + "/workspace-template/{templateName}/prebuild": { + "get": { + "description": "List prebuilds for workspace template", + "consumes": [ "application/json" ], "tags": [ - "workspace toolbox" + "prebuild" ], - "summary": "Add files", - "operationId": "GitAddFiles", + "summary": "List prebuilds for workspace template", + "operationId": "ListPrebuildsForWorkspaceTemplate", "parameters": [ { "type": "string", - "description": "Workspace ID or Name", - "name": "workspaceId", + "description": "Template name", + "name": "templateName", "in": "path", "required": true - }, + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/PrebuildDTO" + } + } + } + } + }, + "put": { + "description": "Save prebuild", + "consumes": [ + "application/json" + ], + "tags": [ + "prebuild" + ], + "summary": "Save prebuild", + "operationId": "SavePrebuild", + "parameters": [ { "type": "string", - "description": "Project ID", - "name": "projectId", + "description": "Template name", + "name": "templateName", "in": "path", "required": true }, { - "description": "GitAddRequest", - "name": "params", + "description": "Prebuild", + "name": "prebuild", "in": "body", "required": true, "schema": { - "$ref": "#/definitions/GitAddRequest" + "$ref": "#/definitions/CreatePrebuildDTO" } } ], "responses": { - "200": { - "description": "OK" + "201": { + "description": "Created", + "schema": { + "type": "string" + } } } } }, - "/workspace/{workspaceId}/{projectId}/toolbox/git/branches": { + "/workspace-template/{templateName}/prebuild/{prebuildId}": { "get": { - "description": "Get branch list from git repository inside workspace project", - "produces": [ + "description": "Find prebuild", + "consumes": [ "application/json" ], "tags": [ - "workspace toolbox" + "prebuild" ], - "summary": "Get branch list", - "operationId": "GitBranchList", + "summary": "Find prebuild", + "operationId": "FindPrebuild", "parameters": [ { "type": "string", - "description": "Workspace ID or Name", - "name": "workspaceId", + "description": "Workspace template name", + "name": "templateName", "in": "path", "required": true }, { "type": "string", - "description": "Project ID", - "name": "projectId", + "description": "Prebuild ID", + "name": "prebuildId", "in": "path", "required": true - }, - { - "type": "string", - "description": "Path to git repository", - "name": "path", - "in": "query", - "required": true } ], "responses": { "200": { "description": "OK", "schema": { - "$ref": "#/definitions/ListBranchResponse" + "$ref": "#/definitions/PrebuildDTO" } } } }, - "post": { - "description": "Create branch on git repository inside workspace project", - "produces": [ + "delete": { + "description": "Delete prebuild", + "consumes": [ "application/json" ], "tags": [ - "workspace toolbox" + "prebuild" ], - "summary": "Create branch", - "operationId": "GitCreateBranch", + "summary": "Delete prebuild", + "operationId": "DeletePrebuild", "parameters": [ { "type": "string", - "description": "Workspace ID or Name", - "name": "workspaceId", + "description": "Workspace template name", + "name": "templateName", "in": "path", "required": true }, { "type": "string", - "description": "Project ID", - "name": "projectId", + "description": "Prebuild ID", + "name": "prebuildId", "in": "path", "required": true }, { - "description": "GitBranchRequest", - "name": "params", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/GitBranchRequest" - } + "type": "boolean", + "description": "Force", + "name": "force", + "in": "query" } ], "responses": { - "201": { - "description": "Created" + "204": { + "description": "No Content" } } } }, - "/workspace/{workspaceId}/{projectId}/toolbox/git/clone": { - "post": { - "description": "Clone git repository inside workspace project", - "produces": [ - "application/json" - ], + "/workspace-template/{templateName}/set-default": { + "patch": { + "description": "Set workspace template to default", "tags": [ - "workspace toolbox" + "workspace-template" ], - "summary": "Clone git repository", - "operationId": "GitCloneRepository", + "summary": "Set workspace template to default", + "operationId": "SetDefaultWorkspaceTemplate", "parameters": [ { "type": "string", - "description": "Workspace ID or Name", - "name": "workspaceId", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Project ID", - "name": "projectId", + "description": "Template name", + "name": "templateName", "in": "path", "required": true - }, - { - "description": "GitCloneRequest", - "name": "params", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/GitCloneRequest" - } } ], "responses": { @@ -2579,17 +2335,17 @@ } } }, - "/workspace/{workspaceId}/{projectId}/toolbox/git/commit": { - "post": { - "description": "Commit changes to git repository inside workspace project", + "/workspace/{workspaceId}": { + "get": { + "description": "Find workspace", "produces": [ "application/json" ], "tags": [ - "workspace toolbox" + "workspace" ], - "summary": "Commit changes", - "operationId": "GitCommitChanges", + "summary": "Find workspace", + "operationId": "FindWorkspace", "parameters": [ { "type": "string", @@ -2597,45 +2353,54 @@ "name": "workspaceId", "in": "path", "required": true - }, + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/WorkspaceDTO" + } + } + } + }, + "delete": { + "description": "Delete workspace", + "tags": [ + "workspace" + ], + "summary": "Delete workspace", + "operationId": "DeleteWorkspace", + "parameters": [ { "type": "string", - "description": "Project ID", - "name": "projectId", + "description": "Workspace ID", + "name": "workspaceId", "in": "path", "required": true }, { - "description": "GitCommitRequest", - "name": "params", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/GitCommitRequest" - } + "type": "boolean", + "description": "Force", + "name": "force", + "in": "query" } ], "responses": { "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/GitCommitResponse" - } + "description": "OK" } } } }, - "/workspace/{workspaceId}/{projectId}/toolbox/git/history": { - "get": { - "description": "Get commit history from git repository inside workspace project", - "produces": [ - "application/json" - ], + "/workspace/{workspaceId}/labels": { + "post": { + "description": "Update workspace labels", "tags": [ - "workspace toolbox" + "workspace" ], - "summary": "Get commit history", - "operationId": "GitCommitHistory", + "summary": "Update workspace labels", + "operationId": "UpdateWorkspaceLabels", "parameters": [ { "type": "string", @@ -2645,66 +2410,51 @@ "required": true }, { - "type": "string", - "description": "Project ID", - "name": "projectId", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Path to git repository", - "name": "path", - "in": "query", - "required": true + "description": "Labels", + "name": "labels", + "in": "body", + "required": true, + "schema": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } } ], "responses": { "200": { "description": "OK", "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/GitCommitInfo" - } + "$ref": "#/definitions/WorkspaceDTO" } } } } }, - "/workspace/{workspaceId}/{projectId}/toolbox/git/pull": { + "/workspace/{workspaceId}/metadata": { "post": { - "description": "Pull changes from remote to git repository inside workspace project", - "produces": [ - "application/json" - ], + "description": "Update workspace metadata", "tags": [ - "workspace toolbox" + "workspace" ], - "summary": "Pull changes", - "operationId": "GitPullChanges", + "summary": "Update workspace metadata", + "operationId": "UpdateWorkspaceMetadata", "parameters": [ { "type": "string", - "description": "Workspace ID or Name", + "description": "Workspace ID", "name": "workspaceId", "in": "path", "required": true }, { - "type": "string", - "description": "Project ID", - "name": "projectId", - "in": "path", - "required": true - }, - { - "description": "Git pull request", - "name": "params", + "description": "Workspace Metadata", + "name": "workspaceMetadata", "in": "body", "required": true, "schema": { - "$ref": "#/definitions/GitRepoRequest" + "$ref": "#/definitions/UpdateWorkspaceMetadataDTO" } } ], @@ -2715,39 +2465,29 @@ } } }, - "/workspace/{workspaceId}/{projectId}/toolbox/git/push": { + "/workspace/{workspaceId}/provider-metadata": { "post": { - "description": "Push changes to remote from git repository inside workspace project", - "produces": [ - "application/json" - ], + "description": "Update workspace provider metadata", "tags": [ - "workspace toolbox" + "workspace" ], - "summary": "Push changes", - "operationId": "GitPushChanges", + "summary": "Update workspace provider metadata", + "operationId": "UpdateWorkspaceProviderMetadata", "parameters": [ { "type": "string", - "description": "Workspace ID or Name", + "description": "Workspace ID", "name": "workspaceId", "in": "path", "required": true }, { - "type": "string", - "description": "Project ID", - "name": "projectId", - "in": "path", - "required": true - }, - { - "description": "Git push request", - "name": "params", + "description": "Provider metadata", + "name": "metadata", "in": "body", "required": true, "schema": { - "$ref": "#/definitions/GitRepoRequest" + "$ref": "#/definitions/UpdateWorkspaceProviderMetadataDTO" } } ], @@ -2758,17 +2498,14 @@ } } }, - "/workspace/{workspaceId}/{projectId}/toolbox/git/status": { - "get": { - "description": "Get status from git repository inside workspace project", - "produces": [ - "application/json" - ], + "/workspace/{workspaceId}/restart": { + "post": { + "description": "Restart workspace", "tags": [ - "workspace toolbox" + "workspace" ], - "summary": "Get git status", - "operationId": "GitGitStatus", + "summary": "Restart workspace", + "operationId": "RestartWorkspace", "parameters": [ { "type": "string", @@ -2776,43 +2513,50 @@ "name": "workspaceId", "in": "path", "required": true - }, + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/workspace/{workspaceId}/start": { + "post": { + "description": "Start workspace", + "tags": [ + "workspace" + ], + "summary": "Start workspace", + "operationId": "StartWorkspace", + "parameters": [ { "type": "string", - "description": "Project ID", - "name": "projectId", + "description": "Workspace ID or Name", + "name": "workspaceId", "in": "path", "required": true - }, - { - "type": "string", - "description": "Path to git repository", - "name": "path", - "in": "query", - "required": true } ], "responses": { "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/GitStatus" - } + "description": "OK" } } } }, - "/workspace/{workspaceId}/{projectId}/toolbox/lsp/completions": { - "post": { - "description": "The Completion request is sent from the client to the server to compute completion items at a given cursor position.", + "/workspace/{workspaceId}/state": { + "get": { + "description": "Get workspace state", "produces": [ "application/json" ], "tags": [ - "workspace toolbox" + "workspace" ], - "summary": "Get Lsp Completions", - "operationId": "LspCompletions", + "summary": "Get workspace state", + "operationId": "GetWorkspaceState", "parameters": [ { "type": "string", @@ -2820,45 +2564,26 @@ "name": "workspaceId", "in": "path", "required": true - }, - { - "type": "string", - "description": "Project ID", - "name": "projectId", - "in": "path", - "required": true - }, - { - "description": "LspCompletionParams", - "name": "params", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/LspCompletionParams" - } } ], "responses": { "200": { "description": "OK", "schema": { - "$ref": "#/definitions/CompletionList" + "$ref": "#/definitions/ResourceState" } } } } }, - "/workspace/{workspaceId}/{projectId}/toolbox/lsp/did-close": { + "/workspace/{workspaceId}/stop": { "post": { - "description": "The document close notification is sent from the client to the server when the document got closed in the client.", - "produces": [ - "application/json" - ], + "description": "Stop workspace", "tags": [ - "workspace toolbox" + "workspace" ], - "summary": "Call Lsp DidClose", - "operationId": "LspDidClose", + "summary": "Stop workspace", + "operationId": "StopWorkspace", "parameters": [ { "type": "string", @@ -2866,22 +2591,6 @@ "name": "workspaceId", "in": "path", "required": true - }, - { - "type": "string", - "description": "Project ID", - "name": "projectId", - "in": "path", - "required": true - }, - { - "description": "LspDocumentRequest", - "name": "params", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/LspDocumentRequest" - } } ], "responses": { @@ -2891,17 +2600,17 @@ } } }, - "/workspace/{workspaceId}/{projectId}/toolbox/lsp/did-open": { - "post": { - "description": "The document open notification is sent from the client to the server to signal newly opened text documents.", + "/workspace/{workspaceId}/toolbox/files": { + "get": { + "description": "List files inside a workspace", "produces": [ "application/json" ], "tags": [ "workspace toolbox" ], - "summary": "Call Lsp DidOpen", - "operationId": "LspDidOpen", + "summary": "List files", + "operationId": "FsListFiles", "parameters": [ { "type": "string", @@ -2912,39 +2621,33 @@ }, { "type": "string", - "description": "Project ID", - "name": "projectId", - "in": "path", - "required": true - }, - { - "description": "LspDocumentRequest", - "name": "params", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/LspDocumentRequest" - } + "description": "Path", + "name": "path", + "in": "query" } ], "responses": { "200": { - "description": "OK" + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/FileInfo" + } + } } } - } - }, - "/workspace/{workspaceId}/{projectId}/toolbox/lsp/document-symbols": { - "get": { - "description": "The document symbol request is sent from the client to the server.", + }, + "delete": { + "description": "Delete file inside a workspace", "produces": [ "application/json" ], "tags": [ "workspace toolbox" ], - "summary": "Call Lsp DocumentSymbols", - "operationId": "LspDocumentSymbols", + "summary": "Delete file", + "operationId": "FsDeleteFile", "parameters": [ { "type": "string", @@ -2955,57 +2658,67 @@ }, { "type": "string", - "description": "Project ID", - "name": "projectId", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Language ID", - "name": "languageId", + "description": "Path", + "name": "path", "in": "query", "required": true - }, + } + ], + "responses": { + "204": { + "description": "No Content" + } + } + } + }, + "/workspace/{workspaceId}/toolbox/files/download": { + "get": { + "description": "Download file from a workspace", + "produces": [ + "application/json" + ], + "tags": [ + "workspace toolbox" + ], + "summary": "Download file", + "operationId": "FsDownloadFile", + "parameters": [ { "type": "string", - "description": "Path to project", - "name": "pathToProject", - "in": "query", + "description": "Workspace ID or Name", + "name": "workspaceId", + "in": "path", "required": true }, { "type": "string", - "description": "Document Uri", - "name": "uri", + "description": "Path", + "name": "path", "in": "query", "required": true } ], "responses": { "200": { - "description": "OK", + "description": "response contains the file", "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/LspSymbol" - } + "type": "file" } } } } }, - "/workspace/{workspaceId}/{projectId}/toolbox/lsp/start": { - "post": { - "description": "Start Lsp server process inside workspace project", + "/workspace/{workspaceId}/toolbox/files/find": { + "get": { + "description": "Search for text/pattern inside a workspace files", "produces": [ "application/json" ], "tags": [ "workspace toolbox" ], - "summary": "Start Lsp server", - "operationId": "LspStart", + "summary": "Search for text/pattern in files", + "operationId": "FsFindInFiles", "parameters": [ { "type": "string", @@ -3016,39 +2729,43 @@ }, { "type": "string", - "description": "Project ID", - "name": "projectId", - "in": "path", + "description": "Path", + "name": "path", + "in": "query", "required": true }, { - "description": "LspServerRequest", - "name": "params", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/LspServerRequest" - } + "type": "string", + "description": "Pattern", + "name": "pattern", + "in": "query", + "required": true } ], "responses": { "200": { - "description": "OK" + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/Match" + } + } } } } }, - "/workspace/{workspaceId}/{projectId}/toolbox/lsp/stop": { + "/workspace/{workspaceId}/toolbox/files/folder": { "post": { - "description": "Stop Lsp server process inside workspace project", + "description": "Create folder inside a workspace", "produces": [ "application/json" ], "tags": [ "workspace toolbox" ], - "summary": "Stop Lsp server", - "operationId": "LspStop", + "summary": "Create folder", + "operationId": "FsCreateFolder", "parameters": [ { "type": "string", @@ -3059,39 +2776,37 @@ }, { "type": "string", - "description": "Project ID", - "name": "projectId", - "in": "path", + "description": "Path", + "name": "path", + "in": "query", "required": true }, { - "description": "LspServerRequest", - "name": "params", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/LspServerRequest" - } + "type": "string", + "description": "Mode", + "name": "mode", + "in": "query", + "required": true } ], "responses": { - "200": { - "description": "OK" + "201": { + "description": "Created" } } } }, - "/workspace/{workspaceId}/{projectId}/toolbox/lsp/workspace-symbols": { + "/workspace/{workspaceId}/toolbox/files/info": { "get": { - "description": "The workspace symbol request is sent from the client to the server to list project-wide symbols matching the query string.", + "description": "Get file info inside a workspace", "produces": [ "application/json" ], "tags": [ "workspace toolbox" ], - "summary": "Call Lsp WorkspaceSymbols", - "operationId": "LspWorkspaceSymbols", + "summary": "Get file info", + "operationId": "FsGetFileDetails", "parameters": [ { "type": "string", @@ -3102,29 +2817,8 @@ }, { "type": "string", - "description": "Project ID", - "name": "projectId", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Language ID", - "name": "languageId", - "in": "query", - "required": true - }, - { - "type": "string", - "description": "Path to project", - "name": "pathToProject", - "in": "query", - "required": true - }, - { - "type": "string", - "description": "Symbol Query", - "name": "query", + "description": "Path", + "name": "path", "in": "query", "required": true } @@ -3133,26 +2827,23 @@ "200": { "description": "OK", "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/LspSymbol" - } + "$ref": "#/definitions/FileInfo" } } } } }, - "/workspace/{workspaceId}/{projectId}/toolbox/process/execute": { + "/workspace/{workspaceId}/toolbox/files/move": { "post": { - "description": "Execute command synchronously inside workspace project", + "description": "Create folder inside a workspace", "produces": [ "application/json" ], "tags": [ "workspace toolbox" ], - "summary": "Execute command", - "operationId": "ProcessExecuteCommand", + "summary": "Create folder", + "operationId": "FsMoveFile", "parameters": [ { "type": "string", @@ -3163,42 +2854,37 @@ }, { "type": "string", - "description": "Project ID", - "name": "projectId", - "in": "path", + "description": "Source path", + "name": "source", + "in": "query", "required": true }, { - "description": "Execute command request", - "name": "params", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/ExecuteRequest" - } + "type": "string", + "description": "Destination path", + "name": "destination", + "in": "query", + "required": true } ], "responses": { "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/ExecuteResponse" - } + "description": "OK" } } } }, - "/workspace/{workspaceId}/{projectId}/toolbox/process/session": { - "get": { - "description": "List sessions inside workspace project", + "/workspace/{workspaceId}/toolbox/files/permissions": { + "post": { + "description": "Set file owner/group/permissions inside a workspace", "produces": [ "application/json" ], "tags": [ "workspace toolbox" ], - "summary": "List sessions", - "operationId": "ListSessions", + "summary": "Set file owner/group/permissions", + "operationId": "FsSetFilePermissions", "parameters": [ { "type": "string", @@ -3209,34 +2895,48 @@ }, { "type": "string", - "description": "Project ID", - "name": "projectId", - "in": "path", + "description": "Path", + "name": "path", + "in": "query", "required": true + }, + { + "type": "string", + "description": "Owner", + "name": "owner", + "in": "query" + }, + { + "type": "string", + "description": "Group", + "name": "group", + "in": "query" + }, + { + "type": "string", + "description": "Mode", + "name": "mode", + "in": "query" } ], "responses": { "200": { - "description": "OK", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/Session" - } - } + "description": "OK" } } - }, + } + }, + "/workspace/{workspaceId}/toolbox/files/replace": { "post": { - "description": "Create exec session inside workspace project", + "description": "Repleace text/pattern in mutilple files inside a workspace", "produces": [ "application/json" ], "tags": [ "workspace toolbox" ], - "summary": "Create exec session", - "operationId": "CreateSession", + "summary": "Repleace text/pattern in files", + "operationId": "FsReplaceInFiles", "parameters": [ { "type": "string", @@ -3246,40 +2946,39 @@ "required": true }, { - "type": "string", - "description": "Project ID", - "name": "projectId", - "in": "path", - "required": true - }, - { - "description": "Create session request", - "name": "params", + "description": "ReplaceParams", + "name": "replace", "in": "body", "required": true, "schema": { - "$ref": "#/definitions/CreateSessionRequest" + "$ref": "#/definitions/ReplaceRequest" } } ], "responses": { - "201": { - "description": "Created" + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/ReplaceResult" + } + } } } } }, - "/workspace/{workspaceId}/{projectId}/toolbox/process/session/{sessionId}": { - "delete": { - "description": "Delete a session inside workspace project", + "/workspace/{workspaceId}/toolbox/files/search": { + "get": { + "description": "Search for files inside a workspace", "produces": [ "application/json" ], "tags": [ "workspace toolbox" ], - "summary": "Delete session", - "operationId": "DeleteSession", + "summary": "Search for files", + "operationId": "FsSearchFiles", "parameters": [ { "type": "string", @@ -3290,34 +2989,40 @@ }, { "type": "string", - "description": "Project ID", - "name": "projectId", - "in": "path", + "description": "Path", + "name": "path", + "in": "query", "required": true }, { "type": "string", - "description": "Session ID", - "name": "sessionId", - "in": "path", + "description": "Pattern", + "name": "pattern", + "in": "query", "required": true } ], "responses": { - "204": { - "description": "No Content" + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/SearchFilesResponse" + } } } } }, - "/workspace/{workspaceId}/{projectId}/toolbox/process/session/{sessionId}/command/{commandId}/logs": { - "get": { - "description": "Get logs of a command inside a session inside workspace project\nConnect with websocket to get a stream of the logs", + "/workspace/{workspaceId}/toolbox/files/upload": { + "post": { + "description": "Upload file inside a workspace", + "produces": [ + "application/json" + ], "tags": [ "workspace toolbox" ], - "summary": "Get session command logs", - "operationId": "GetSessionCommandLogs", + "summary": "Upload file", + "operationId": "FsUploadFile", "parameters": [ { "type": "string", @@ -3328,16 +3033,809 @@ }, { "type": "string", - "description": "Project ID", - "name": "projectId", - "in": "path", + "description": "Path", + "name": "path", + "in": "query", "required": true }, { - "type": "string", - "description": "Session ID", - "name": "sessionId", - "in": "path", + "type": "file", + "description": "File", + "name": "file", + "in": "formData", + "required": true + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/workspace/{workspaceId}/toolbox/git/add": { + "post": { + "description": "Add files to git commit", + "produces": [ + "application/json" + ], + "tags": [ + "workspace toolbox" + ], + "summary": "Add files", + "operationId": "GitAddFiles", + "parameters": [ + { + "type": "string", + "description": "Workspace ID or Name", + "name": "workspaceId", + "in": "path", + "required": true + }, + { + "description": "GitAddRequest", + "name": "params", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/GitAddRequest" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/workspace/{workspaceId}/toolbox/git/branches": { + "get": { + "description": "Get branch list from git repository inside a workspace", + "produces": [ + "application/json" + ], + "tags": [ + "workspace toolbox" + ], + "summary": "Get branch list", + "operationId": "GitBranchList", + "parameters": [ + { + "type": "string", + "description": "Workspace ID or Name", + "name": "workspaceId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Path to git repository", + "name": "path", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/ListBranchResponse" + } + } + } + }, + "post": { + "description": "Create branch on git repository inside a workspace", + "produces": [ + "application/json" + ], + "tags": [ + "workspace toolbox" + ], + "summary": "Create branch", + "operationId": "GitCreateBranch", + "parameters": [ + { + "type": "string", + "description": "Workspace ID or Name", + "name": "workspaceId", + "in": "path", + "required": true + }, + { + "description": "GitBranchRequest", + "name": "params", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/GitBranchRequest" + } + } + ], + "responses": { + "201": { + "description": "Created" + } + } + } + }, + "/workspace/{workspaceId}/toolbox/git/clone": { + "post": { + "description": "Clone git repository inside a workspace", + "produces": [ + "application/json" + ], + "tags": [ + "workspace toolbox" + ], + "summary": "Clone git repository", + "operationId": "GitCloneRepository", + "parameters": [ + { + "type": "string", + "description": "Workspace ID or Name", + "name": "workspaceId", + "in": "path", + "required": true + }, + { + "description": "GitCloneRequest", + "name": "params", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/GitCloneRequest" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/workspace/{workspaceId}/toolbox/git/commit": { + "post": { + "description": "Commit changes to git repository inside a workspace", + "produces": [ + "application/json" + ], + "tags": [ + "workspace toolbox" + ], + "summary": "Commit changes", + "operationId": "GitCommitChanges", + "parameters": [ + { + "type": "string", + "description": "Workspace ID or Name", + "name": "workspaceId", + "in": "path", + "required": true + }, + { + "description": "GitCommitRequest", + "name": "params", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/GitCommitRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/GitCommitResponse" + } + } + } + } + }, + "/workspace/{workspaceId}/toolbox/git/history": { + "get": { + "description": "Get commit history from git repository inside a workspace", + "produces": [ + "application/json" + ], + "tags": [ + "workspace toolbox" + ], + "summary": "Get commit history", + "operationId": "GitCommitHistory", + "parameters": [ + { + "type": "string", + "description": "Workspace ID or Name", + "name": "workspaceId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Path to git repository", + "name": "path", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/GitCommitInfo" + } + } + } + } + } + }, + "/workspace/{workspaceId}/toolbox/git/pull": { + "post": { + "description": "Pull changes from remote to git repository inside a workspace", + "produces": [ + "application/json" + ], + "tags": [ + "workspace toolbox" + ], + "summary": "Pull changes", + "operationId": "GitPullChanges", + "parameters": [ + { + "type": "string", + "description": "Workspace ID or Name", + "name": "workspaceId", + "in": "path", + "required": true + }, + { + "description": "Git pull request", + "name": "params", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/GitRepoRequest" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/workspace/{workspaceId}/toolbox/git/push": { + "post": { + "description": "Push changes to remote from git repository inside a workspace", + "produces": [ + "application/json" + ], + "tags": [ + "workspace toolbox" + ], + "summary": "Push changes", + "operationId": "GitPushChanges", + "parameters": [ + { + "type": "string", + "description": "Workspace ID or Name", + "name": "workspaceId", + "in": "path", + "required": true + }, + { + "description": "Git push request", + "name": "params", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/GitRepoRequest" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/workspace/{workspaceId}/toolbox/git/status": { + "get": { + "description": "Get status from git repository inside a workspace", + "produces": [ + "application/json" + ], + "tags": [ + "workspace toolbox" + ], + "summary": "Get git status", + "operationId": "GitGitStatus", + "parameters": [ + { + "type": "string", + "description": "Workspace ID or Name", + "name": "workspaceId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Path to git repository", + "name": "path", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/GitStatus" + } + } + } + } + }, + "/workspace/{workspaceId}/toolbox/lsp/completions": { + "post": { + "description": "The Completion request is sent from the client to the server to compute completion items at a given cursor position.", + "produces": [ + "application/json" + ], + "tags": [ + "workspace toolbox" + ], + "summary": "Get Lsp Completions", + "operationId": "LspCompletions", + "parameters": [ + { + "type": "string", + "description": "Workspace ID or Name", + "name": "workspaceId", + "in": "path", + "required": true + }, + { + "description": "LspCompletionParams", + "name": "params", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/LspCompletionParams" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/CompletionList" + } + } + } + } + }, + "/workspace/{workspaceId}/toolbox/lsp/did-close": { + "post": { + "description": "The document close notification is sent from the client to the server when the document got closed in the client.", + "produces": [ + "application/json" + ], + "tags": [ + "workspace toolbox" + ], + "summary": "Call Lsp DidClose", + "operationId": "LspDidClose", + "parameters": [ + { + "type": "string", + "description": "Workspace ID or Name", + "name": "workspaceId", + "in": "path", + "required": true + }, + { + "description": "LspDocumentRequest", + "name": "params", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/LspDocumentRequest" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/workspace/{workspaceId}/toolbox/lsp/did-open": { + "post": { + "description": "The document open notification is sent from the client to the server to signal newly opened text documents.", + "produces": [ + "application/json" + ], + "tags": [ + "workspace toolbox" + ], + "summary": "Call Lsp DidOpen", + "operationId": "LspDidOpen", + "parameters": [ + { + "type": "string", + "description": "Workspace ID or Name", + "name": "workspaceId", + "in": "path", + "required": true + }, + { + "description": "LspDocumentRequest", + "name": "params", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/LspDocumentRequest" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/workspace/{workspaceId}/toolbox/lsp/document-symbols": { + "get": { + "description": "The document symbol request is sent from the client to the server.", + "produces": [ + "application/json" + ], + "tags": [ + "workspace toolbox" + ], + "summary": "Call Lsp DocumentSymbols", + "operationId": "LspDocumentSymbols", + "parameters": [ + { + "type": "string", + "description": "Workspace ID or Name", + "name": "workspaceId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Language ID", + "name": "languageId", + "in": "query", + "required": true + }, + { + "type": "string", + "description": "Path to project", + "name": "pathToProject", + "in": "query", + "required": true + }, + { + "type": "string", + "description": "Document Uri", + "name": "uri", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/LspSymbol" + } + } + } + } + } + }, + "/workspace/{workspaceId}/toolbox/lsp/start": { + "post": { + "description": "Start Lsp server process inside a workspace", + "produces": [ + "application/json" + ], + "tags": [ + "workspace toolbox" + ], + "summary": "Start Lsp server", + "operationId": "LspStart", + "parameters": [ + { + "type": "string", + "description": "Workspace ID or Name", + "name": "workspaceId", + "in": "path", + "required": true + }, + { + "description": "LspServerRequest", + "name": "params", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/LspServerRequest" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/workspace/{workspaceId}/toolbox/lsp/stop": { + "post": { + "description": "Stop Lsp server process inside a workspace", + "produces": [ + "application/json" + ], + "tags": [ + "workspace toolbox" + ], + "summary": "Stop Lsp server", + "operationId": "LspStop", + "parameters": [ + { + "type": "string", + "description": "Workspace ID or Name", + "name": "workspaceId", + "in": "path", + "required": true + }, + { + "description": "LspServerRequest", + "name": "params", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/LspServerRequest" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/workspace/{workspaceId}/toolbox/lsp/workspace-symbols": { + "get": { + "description": "The workspace symbol request is sent from the client to the server to list project-wide symbols matching the query string.", + "produces": [ + "application/json" + ], + "tags": [ + "workspace toolbox" + ], + "summary": "Call Lsp WorkspaceSymbols", + "operationId": "LspWorkspaceSymbols", + "parameters": [ + { + "type": "string", + "description": "Workspace ID or Name", + "name": "workspaceId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Language ID", + "name": "languageId", + "in": "query", + "required": true + }, + { + "type": "string", + "description": "Path to project", + "name": "pathToProject", + "in": "query", + "required": true + }, + { + "type": "string", + "description": "Symbol Query", + "name": "query", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/LspSymbol" + } + } + } + } + } + }, + "/workspace/{workspaceId}/toolbox/process/execute": { + "post": { + "description": "Execute command synchronously inside a workspace", + "produces": [ + "application/json" + ], + "tags": [ + "workspace toolbox" + ], + "summary": "Execute command", + "operationId": "ProcessExecuteCommand", + "parameters": [ + { + "type": "string", + "description": "Workspace ID or Name", + "name": "workspaceId", + "in": "path", + "required": true + }, + { + "description": "Execute command request", + "name": "params", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/ExecuteRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/ExecuteResponse" + } + } + } + } + }, + "/workspace/{workspaceId}/toolbox/process/session": { + "get": { + "description": "List sessions inside workspace project", + "produces": [ + "application/json" + ], + "tags": [ + "workspace toolbox" + ], + "summary": "List sessions", + "operationId": "ListSessions", + "parameters": [ + { + "type": "string", + "description": "Workspace ID or Name", + "name": "workspaceId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/Session" + } + } + } + } + }, + "post": { + "description": "Create exec session inside workspace project", + "produces": [ + "application/json" + ], + "tags": [ + "workspace toolbox" + ], + "summary": "Create exec session", + "operationId": "CreateSession", + "parameters": [ + { + "type": "string", + "description": "Workspace ID or Name", + "name": "workspaceId", + "in": "path", + "required": true + }, + { + "description": "Create session request", + "name": "params", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/CreateSessionRequest" + } + } + ], + "responses": { + "201": { + "description": "Created" + } + } + } + }, + "/workspace/{workspaceId}/toolbox/process/session/{sessionId}": { + "delete": { + "description": "Delete a session inside workspace project", + "produces": [ + "application/json" + ], + "tags": [ + "workspace toolbox" + ], + "summary": "Delete session", + "operationId": "DeleteSession", + "parameters": [ + { + "type": "string", + "description": "Workspace ID or Name", + "name": "workspaceId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Session ID", + "name": "sessionId", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "No Content" + } + } + } + }, + "/workspace/{workspaceId}/toolbox/process/session/{sessionId}/command/{commandId}/logs": { + "get": { + "description": "Get logs of a command inside a session inside workspace project\nConnect with websocket to get a stream of the logs", + "tags": [ + "workspace toolbox" + ], + "summary": "Get session command logs", + "operationId": "GetSessionCommandLogs", + "parameters": [ + { + "type": "string", + "description": "Workspace ID or Name", + "name": "workspaceId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Session ID", + "name": "sessionId", + "in": "path", "required": true }, { @@ -3358,7 +3856,7 @@ } } }, - "/workspace/{workspaceId}/{projectId}/toolbox/process/session/{sessionId}/exec": { + "/workspace/{workspaceId}/toolbox/process/session/{sessionId}/exec": { "post": { "description": "Execute command inside a session inside workspace project", "produces": [ @@ -3377,13 +3875,6 @@ "in": "path", "required": true }, - { - "type": "string", - "description": "Project ID", - "name": "projectId", - "in": "path", - "required": true - }, { "type": "string", "description": "Session ID", @@ -3411,17 +3902,17 @@ } } }, - "/workspace/{workspaceId}/{projectId}/toolbox/project-dir": { + "/workspace/{workspaceId}/toolbox/workspace-dir": { "get": { - "description": "Get project directory", + "description": "Get workspace directory", "produces": [ "application/json" ], "tags": [ "workspace toolbox" ], - "summary": "Get project dir", - "operationId": "GetProjectDir", + "summary": "Get workspace dir", + "operationId": "GetWorkspaceDir", "parameters": [ { "type": "string", @@ -3429,20 +3920,13 @@ "name": "workspaceId", "in": "path", "required": true - }, - { - "type": "string", - "description": "Project ID", - "name": "projectId", - "in": "path", - "required": true } ], "responses": { "200": { "description": "OK", "schema": { - "$ref": "#/definitions/ProjectDirResponse" + "$ref": "#/definitions/WorkspaceDirResponse" } } } @@ -3450,34 +3934,43 @@ } }, "definitions": { - "ApiKey": { + "ApiKeyViewDTO": { "type": "object", "required": [ - "keyHash", + "current", "name", "type" ], "properties": { - "keyHash": { - "type": "string" + "current": { + "type": "boolean" }, "name": { - "description": "Project or client name", "type": "string" }, "type": { - "$ref": "#/definitions/apikey.ApiKeyType" + "$ref": "#/definitions/models.ApiKeyType" + } + } + }, + "BuildConfig": { + "type": "object", + "properties": { + "cachedBuild": { + "$ref": "#/definitions/CachedBuild" + }, + "devcontainer": { + "$ref": "#/definitions/DevcontainerConfig" } } }, - "Build": { + "BuildDTO": { "type": "object", "required": [ "containerConfig", "createdAt", "envVars", "id", - "prebuildId", "repository", "state", "updatedAt" @@ -3504,6 +3997,12 @@ "image": { "type": "string" }, + "lastJob": { + "$ref": "#/definitions/Job" + }, + "lastJobId": { + "type": "string" + }, "prebuildId": { "type": "string" }, @@ -3511,7 +4010,7 @@ "$ref": "#/definitions/GitRepository" }, "state": { - "$ref": "#/definitions/build.BuildState" + "$ref": "#/definitions/ResourceState" }, "updatedAt": { "type": "string" @@ -3521,17 +4020,6 @@ } } }, - "BuildConfig": { - "type": "object", - "properties": { - "cachedBuild": { - "$ref": "#/definitions/CachedBuild" - }, - "devcontainer": { - "$ref": "#/definitions/DevcontainerConfig" - } - } - }, "CachedBuild": { "type": "object", "required": [ @@ -3674,7 +4162,7 @@ "required": [ "branch", "envVars", - "projectConfigName" + "workspaceTemplateName" ], "properties": { "branch": { @@ -3689,7 +4177,7 @@ "prebuildId": { "type": "string" }, - "projectConfigName": { + "workspaceTemplateName": { "type": "string" } } @@ -3720,46 +4208,101 @@ } } }, - "CreateProjectConfigDTO": { + "CreateRunnerDTO": { "type": "object", "required": [ - "envVars", - "name", - "repositoryUrl" + "id", + "name" ], "properties": { - "buildConfig": { - "$ref": "#/definitions/BuildConfig" - }, - "envVars": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "id": { + "type": "string" }, - "gitProviderConfigId": { + "name": { + "type": "string" + } + } + }, + "CreateRunnerResultDTO": { + "type": "object", + "required": [ + "apiKey", + "id", + "name" + ], + "properties": { + "apiKey": { "type": "string" }, - "image": { + "id": { "type": "string" }, + "metadata": { + "$ref": "#/definitions/RunnerMetadata" + }, + "name": { + "type": "string" + } + } + }, + "CreateSessionRequest": { + "type": "object", + "required": [ + "sessionId" + ], + "properties": { + "sessionId": { + "type": "string" + } + } + }, + "CreateTargetConfigDTO": { + "type": "object", + "required": [ + "name", + "options", + "providerInfo" + ], + "properties": { "name": { "type": "string" }, - "repositoryUrl": { + "options": { "type": "string" }, - "user": { + "providerInfo": { + "$ref": "#/definitions/ProviderInfo" + } + } + }, + "CreateTargetDTO": { + "type": "object", + "required": [ + "id", + "name", + "targetConfigId" + ], + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "targetConfigId": { "type": "string" } } }, - "CreateProjectDTO": { + "CreateWorkspaceDTO": { "type": "object", "required": [ "envVars", + "id", + "labels", "name", - "source" + "source", + "targetId" ], "properties": { "buildConfig": { @@ -3774,83 +4317,73 @@ "gitProviderConfigId": { "type": "string" }, + "id": { + "type": "string" + }, "image": { "type": "string" }, + "labels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, "name": { "type": "string" }, "source": { - "$ref": "#/definitions/CreateProjectSourceDTO" + "$ref": "#/definitions/CreateWorkspaceSourceDTO" }, - "user": { - "type": "string" - } - } - }, - "CreateProjectSourceDTO": { - "type": "object", - "required": [ - "repository" - ], - "properties": { - "repository": { - "$ref": "#/definitions/GitRepository" - } - } - }, - "CreateProviderTargetDTO": { - "type": "object", - "required": [ - "name", - "options", - "providerInfo" - ], - "properties": { - "name": { + "targetId": { "type": "string" }, - "options": { + "user": { "type": "string" - }, - "providerInfo": { - "$ref": "#/definitions/provider.ProviderInfo" } } }, - "CreateSessionRequest": { + "CreateWorkspaceSourceDTO": { "type": "object", "required": [ - "sessionId" + "repository" ], "properties": { - "sessionId": { - "type": "string" + "repository": { + "$ref": "#/definitions/GitRepository" } } }, - "CreateWorkspaceDTO": { + "CreateWorkspaceTemplateDTO": { "type": "object", "required": [ - "id", + "envVars", "name", - "projects", - "target" + "repositoryUrl" ], "properties": { - "id": { + "buildConfig": { + "$ref": "#/definitions/BuildConfig" + }, + "envVars": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "gitProviderConfigId": { + "type": "string" + }, + "image": { "type": "string" }, "name": { "type": "string" }, - "projects": { - "type": "array", - "items": { - "$ref": "#/definitions/CreateProjectDTO" - } + "repositoryUrl": { + "type": "string" }, - "target": { + "user": { "type": "string" } } @@ -3866,6 +4399,21 @@ } } }, + "EnvironmentVariable": { + "type": "object", + "required": [ + "key", + "value" + ], + "properties": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + } + } + }, "ExecuteRequest": { "type": "object", "required": [ @@ -4346,24 +4894,66 @@ } } }, - "InstallProviderRequest": { + "Job": { "type": "object", "required": [ - "downloadUrls", - "name" + "action", + "createdAt", + "id", + "resourceId", + "resourceType", + "state", + "updatedAt" ], "properties": { - "downloadUrls": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "action": { + "$ref": "#/definitions/models.JobAction" }, - "name": { + "createdAt": { + "type": "string" + }, + "error": { + "type": "string" + }, + "id": { + "type": "string" + }, + "metadata": { + "description": "JSON encoded metadata", + "type": "string" + }, + "resourceId": { + "type": "string" + }, + "resourceType": { + "$ref": "#/definitions/ResourceType" + }, + "runnerId": { + "type": "string" + }, + "state": { + "$ref": "#/definitions/JobState" + }, + "updatedAt": { "type": "string" } } }, + "JobState": { + "type": "string", + "enum": [ + "pending", + "running", + "error", + "success" + ], + "x-enum-varnames": [ + "JobStatePending", + "JobStateRunning", + "JobStateError", + "JobStateSuccess" + ] + }, "ListBranchResponse": { "type": "object", "required": [ @@ -4580,7 +5170,6 @@ "type": "object", "required": [ "branch", - "commitInterval", "id", "retention", "triggerFiles" @@ -4611,8 +5200,8 @@ "required": [ "branch", "id", - "projectConfigName", - "retention" + "retention", + "workspaceTemplateName" ], "properties": { "branch": { @@ -4624,9 +5213,6 @@ "id": { "type": "string" }, - "projectConfigName": { - "type": "string" - }, "retention": { "type": "integer" }, @@ -4635,260 +5221,195 @@ "items": { "type": "string" } + }, + "workspaceTemplateName": { + "type": "string" } } }, - "ProfileData": { - "type": "object", - "required": [ - "envVars" - ], - "properties": { - "envVars": { - "type": "object", - "additionalProperties": { - "type": "string" - } - } - } - }, - "Project": { + "ProviderDTO": { "type": "object", "required": [ - "envVars", - "image", + "latest", "name", - "repository", - "target", - "user", - "workspaceId" + "version" ], "properties": { - "buildConfig": { - "$ref": "#/definitions/BuildConfig" - }, - "envVars": { - "type": "object", - "additionalProperties": { - "type": "string" - } - }, - "gitProviderConfigId": { + "label": { "type": "string" }, - "image": { - "type": "string" + "latest": { + "type": "boolean" }, "name": { "type": "string" }, - "repository": { - "$ref": "#/definitions/GitRepository" - }, - "state": { - "$ref": "#/definitions/ProjectState" - }, - "target": { - "type": "string" - }, - "user": { - "type": "string" - }, - "workspaceId": { + "version": { "type": "string" } } }, - "ProjectConfig": { + "ProviderInfo": { "type": "object", "required": [ - "default", - "envVars", - "image", "name", - "repositoryUrl", - "user" + "runnerId", + "runnerName", + "targetConfigManifest", + "version" ], "properties": { - "buildConfig": { - "$ref": "#/definitions/BuildConfig" - }, - "default": { + "agentlessTarget": { "type": "boolean" }, - "envVars": { - "type": "object", - "additionalProperties": { - "type": "string" - } - }, - "gitProviderConfigId": { - "type": "string" - }, - "image": { + "label": { "type": "string" }, "name": { "type": "string" }, - "prebuilds": { - "type": "array", - "items": { - "$ref": "#/definitions/PrebuildConfig" - } - }, - "repositoryUrl": { + "runnerId": { "type": "string" }, - "user": { + "runnerName": { "type": "string" - } - } - }, - "ProjectDirResponse": { - "type": "object", - "properties": { - "dir": { + }, + "targetConfigManifest": { + "$ref": "#/definitions/TargetConfigManifest" + }, + "version": { "type": "string" } } }, - "ProjectInfo": { + "ReplaceRequest": { "type": "object", "required": [ - "created", - "isRunning", - "name", - "workspaceId" + "files", + "newValue", + "pattern" ], "properties": { - "created": { - "type": "string" - }, - "isRunning": { - "type": "boolean" - }, - "name": { - "type": "string" + "files": { + "type": "array", + "items": { + "type": "string" + } }, - "providerMetadata": { + "newValue": { "type": "string" }, - "workspaceId": { + "pattern": { "type": "string" } } }, - "ProjectState": { + "ReplaceResult": { "type": "object", - "required": [ - "updatedAt", - "uptime" - ], "properties": { - "gitStatus": { - "$ref": "#/definitions/GitStatus" + "error": { + "type": "string" }, - "updatedAt": { + "file": { "type": "string" }, - "uptime": { - "type": "integer" + "success": { + "type": "boolean" } } }, - "Provider": { + "RepositoryUrl": { "type": "object", "required": [ - "name", - "version" + "url" ], "properties": { - "label": { - "type": "string" - }, - "name": { - "type": "string" - }, - "version": { + "url": { "type": "string" } } }, - "ProviderTarget": { + "ResourceState": { "type": "object", "required": [ - "isDefault", "name", - "options", - "providerInfo" + "updatedAt" ], "properties": { - "isDefault": { - "type": "boolean" + "error": { + "type": "string" }, "name": { - "type": "string" + "$ref": "#/definitions/models.ResourceStateName" }, - "options": { - "description": "JSON encoded map of options", + "updatedAt": { "type": "string" - }, - "providerInfo": { - "$ref": "#/definitions/provider.ProviderInfo" } } }, - "ProviderTargetManifest": { - "type": "object", - "additionalProperties": { - "$ref": "#/definitions/provider.ProviderTargetProperty" - } - }, - "ReplaceRequest": { - "type": "object", - "required": [ - "files", - "newValue", - "pattern" + "ResourceType": { + "type": "string", + "enum": [ + "workspace", + "target", + "build", + "runner" ], - "properties": { - "files": { - "type": "array", - "items": { - "type": "string" - } - }, - "newValue": { - "type": "string" - }, - "pattern": { - "type": "string" - } - } + "x-enum-varnames": [ + "ResourceTypeWorkspace", + "ResourceTypeTarget", + "ResourceTypeBuild", + "ResourceTypeRunner" + ] }, - "ReplaceResult": { + "RunnerDTO": { "type": "object", + "required": [ + "id", + "name", + "state" + ], "properties": { - "error": { + "id": { "type": "string" }, - "file": { + "metadata": { + "$ref": "#/definitions/RunnerMetadata" + }, + "name": { "type": "string" }, - "success": { - "type": "boolean" + "state": { + "$ref": "#/definitions/ResourceState" } } }, - "RepositoryUrl": { + "RunnerMetadata": { "type": "object", "required": [ - "url" + "providers", + "runnerId", + "updatedAt", + "uptime" ], "properties": { - "url": { + "providers": { + "type": "array", + "items": { + "$ref": "#/definitions/ProviderInfo" + } + }, + "runnerId": { + "type": "string" + }, + "runningJobs": { + "type": "integer" + }, + "updatedAt": { "type": "string" + }, + "uptime": { + "type": "integer" } } }, @@ -4932,14 +5453,13 @@ "binariesPath", "builderImage", "builderRegistryServer", - "defaultProjectImage", - "defaultProjectUser", + "defaultWorkspaceImage", + "defaultWorkspaceUser", "headscalePort", "id", "localBuilderRegistryImage", "localBuilderRegistryPort", "logFile", - "providersDir", "registryUrl", "serverDownloadUrl" ], @@ -4959,10 +5479,10 @@ "builderRegistryServer": { "type": "string" }, - "defaultProjectImage": { + "defaultWorkspaceImage": { "type": "string" }, - "defaultProjectUser": { + "defaultWorkspaceUser": { "type": "string" }, "frps": { @@ -4980,12 +5500,12 @@ "localBuilderRegistryPort": { "type": "integer" }, + "localRunnerDisabled": { + "type": "boolean" + }, "logFile": { "$ref": "#/definitions/LogFileConfig" }, - "providersDir": { - "type": "string" - }, "registryUrl": { "type": "string" }, @@ -5076,7 +5596,298 @@ } } }, - "SetProjectState": { + "SigningMethod": { + "type": "string", + "enum": [ + "ssh", + "gpg" + ], + "x-enum-varnames": [ + "SigningMethodSSH", + "SigningMethodGPG" + ] + }, + "Status": { + "type": "string", + "enum": [ + "Unmodified", + "Untracked", + "Modified", + "Added", + "Deleted", + "Renamed", + "Copied", + "Updated but unmerged" + ], + "x-enum-varnames": [ + "Unmodified", + "Untracked", + "Modified", + "Added", + "Deleted", + "Renamed", + "Copied", + "UpdatedButUnmerged" + ] + }, + "Target": { + "type": "object", + "required": [ + "default", + "envVars", + "id", + "name", + "targetConfig", + "targetConfigId", + "workspaces" + ], + "properties": { + "default": { + "type": "boolean" + }, + "envVars": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "id": { + "type": "string" + }, + "lastJob": { + "$ref": "#/definitions/Job" + }, + "lastJobId": { + "type": "string" + }, + "metadata": { + "$ref": "#/definitions/TargetMetadata" + }, + "name": { + "type": "string" + }, + "providerMetadata": { + "type": "string" + }, + "targetConfig": { + "$ref": "#/definitions/TargetConfig" + }, + "targetConfigId": { + "type": "string" + }, + "workspaces": { + "type": "array", + "items": { + "$ref": "#/definitions/Workspace" + } + } + } + }, + "TargetConfig": { + "type": "object", + "required": [ + "deleted", + "id", + "name", + "options", + "providerInfo" + ], + "properties": { + "deleted": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "options": { + "description": "JSON encoded map of options", + "type": "string" + }, + "providerInfo": { + "$ref": "#/definitions/ProviderInfo" + } + } + }, + "TargetConfigManifest": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/TargetConfigProperty" + } + }, + "TargetConfigProperty": { + "type": "object", + "properties": { + "defaultValue": { + "description": "DefaultValue is converted into the appropriate type based on the Type\nIf the property is a FilePath, the DefaultValue is a path to a directory", + "type": "string" + }, + "description": { + "description": "Brief description of the property", + "type": "string" + }, + "disabledPredicate": { + "description": "A regex string matched with the name of the target config to determine if the property should be disabled\nIf the regex matches the target config name, the property will be disabled\nE.g. \"^local$\" will disable the property for the local target", + "type": "string" + }, + "inputMasked": { + "type": "boolean" + }, + "options": { + "description": "Options is only used if the Type is TargetConfigPropertyTypeOption", + "type": "array", + "items": { + "type": "string" + } + }, + "suggestions": { + "description": "Suggestions is an optional list of auto-complete values to assist the user while filling the field", + "type": "array", + "items": { + "type": "string" + } + }, + "type": { + "$ref": "#/definitions/models.TargetConfigPropertyType" + } + } + }, + "TargetDTO": { + "type": "object", + "required": [ + "default", + "envVars", + "id", + "name", + "state", + "targetConfig", + "targetConfigId", + "workspaces" + ], + "properties": { + "default": { + "type": "boolean" + }, + "envVars": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "id": { + "type": "string" + }, + "lastJob": { + "$ref": "#/definitions/Job" + }, + "lastJobId": { + "type": "string" + }, + "metadata": { + "$ref": "#/definitions/TargetMetadata" + }, + "name": { + "type": "string" + }, + "providerMetadata": { + "type": "string" + }, + "state": { + "$ref": "#/definitions/ResourceState" + }, + "targetConfig": { + "$ref": "#/definitions/TargetConfig" + }, + "targetConfigId": { + "type": "string" + }, + "workspaces": { + "type": "array", + "items": { + "$ref": "#/definitions/Workspace" + } + } + } + }, + "TargetMetadata": { + "type": "object", + "required": [ + "targetId", + "updatedAt", + "uptime" + ], + "properties": { + "targetId": { + "type": "string" + }, + "updatedAt": { + "type": "string" + }, + "uptime": { + "type": "integer" + } + } + }, + "UpdateJobState": { + "type": "object", + "required": [ + "state" + ], + "properties": { + "errorMessage": { + "type": "string" + }, + "state": { + "$ref": "#/definitions/JobState" + } + } + }, + "UpdateRunnerMetadataDTO": { + "type": "object", + "required": [ + "providers", + "uptime" + ], + "properties": { + "providers": { + "type": "array", + "items": { + "$ref": "#/definitions/ProviderInfo" + } + }, + "runningJobs": { + "type": "integer" + }, + "uptime": { + "type": "integer" + } + } + }, + "UpdateTargetMetadataDTO": { + "type": "object", + "required": [ + "uptime" + ], + "properties": { + "uptime": { + "type": "integer" + } + } + }, + "UpdateTargetProviderMetadataDTO": { + "type": "object", + "required": [ + "metadata" + ], + "properties": { + "metadata": { + "type": "string" + } + } + }, + "UpdateWorkspaceMetadataDTO": { "type": "object", "required": [ "uptime" @@ -5090,62 +5901,84 @@ } } }, - "SigningMethod": { - "type": "string", - "enum": [ - "ssh", - "gpg" - ], - "x-enum-varnames": [ - "SigningMethodSSH", - "SigningMethodGPG" - ] - }, - "Status": { - "type": "string", - "enum": [ - "Unmodified", - "Untracked", - "Modified", - "Added", - "Deleted", - "Renamed", - "Copied", - "Updated but unmerged" + "UpdateWorkspaceProviderMetadataDTO": { + "type": "object", + "required": [ + "metadata" ], - "x-enum-varnames": [ - "Unmodified", - "Untracked", - "Modified", - "Added", - "Deleted", - "Renamed", - "Copied", - "UpdatedButUnmerged" - ] + "properties": { + "metadata": { + "type": "string" + } + } }, "Workspace": { "type": "object", "required": [ + "apiKey", + "envVars", "id", + "image", + "labels", "name", - "projects", - "target" + "repository", + "target", + "targetId", + "user" ], "properties": { + "apiKey": { + "type": "string" + }, + "buildConfig": { + "$ref": "#/definitions/BuildConfig" + }, + "envVars": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "gitProviderConfigId": { + "type": "string" + }, "id": { "type": "string" }, - "name": { + "image": { "type": "string" }, - "projects": { - "type": "array", - "items": { - "$ref": "#/definitions/Project" + "labels": { + "type": "object", + "additionalProperties": { + "type": "string" } }, + "lastJob": { + "$ref": "#/definitions/Job" + }, + "lastJobId": { + "type": "string" + }, + "metadata": { + "$ref": "#/definitions/WorkspaceMetadata" + }, + "name": { + "type": "string" + }, + "providerMetadata": { + "type": "string" + }, + "repository": { + "$ref": "#/definitions/GitRepository" + }, "target": { + "$ref": "#/definitions/Target" + }, + "targetId": { + "type": "string" + }, + "user": { "type": "string" } } @@ -5153,145 +5986,249 @@ "WorkspaceDTO": { "type": "object", "required": [ + "apiKey", + "envVars", "id", + "image", + "labels", "name", - "projects", - "target" + "repository", + "state", + "target", + "targetId", + "user" ], "properties": { + "apiKey": { + "type": "string" + }, + "buildConfig": { + "$ref": "#/definitions/BuildConfig" + }, + "envVars": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "gitProviderConfigId": { + "type": "string" + }, "id": { "type": "string" }, - "info": { - "$ref": "#/definitions/WorkspaceInfo" + "image": { + "type": "string" + }, + "labels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "lastJob": { + "$ref": "#/definitions/Job" + }, + "lastJobId": { + "type": "string" + }, + "metadata": { + "$ref": "#/definitions/WorkspaceMetadata" }, "name": { "type": "string" }, - "projects": { - "type": "array", - "items": { - "$ref": "#/definitions/Project" - } + "providerMetadata": { + "type": "string" + }, + "repository": { + "$ref": "#/definitions/GitRepository" + }, + "state": { + "$ref": "#/definitions/ResourceState" }, "target": { + "$ref": "#/definitions/Target" + }, + "targetId": { + "type": "string" + }, + "user": { + "type": "string" + } + } + }, + "WorkspaceDirResponse": { + "type": "object", + "properties": { + "dir": { + "type": "string" + } + } + }, + "WorkspaceMetadata": { + "type": "object", + "required": [ + "updatedAt", + "uptime", + "workspaceId" + ], + "properties": { + "gitStatus": { + "$ref": "#/definitions/GitStatus" + }, + "updatedAt": { + "type": "string" + }, + "uptime": { + "type": "integer" + }, + "workspaceId": { "type": "string" } } }, - "WorkspaceInfo": { + "WorkspaceTemplate": { "type": "object", "required": [ + "default", + "envVars", + "image", + "labels", "name", - "projects" + "repositoryUrl", + "user" ], "properties": { + "buildConfig": { + "$ref": "#/definitions/BuildConfig" + }, + "default": { + "type": "boolean" + }, + "envVars": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "gitProviderConfigId": { + "type": "string" + }, + "image": { + "type": "string" + }, + "labels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, "name": { "type": "string" }, - "projects": { + "prebuilds": { "type": "array", "items": { - "$ref": "#/definitions/ProjectInfo" + "$ref": "#/definitions/PrebuildConfig" } }, - "providerMetadata": { + "repositoryUrl": { + "type": "string" + }, + "user": { "type": "string" } } }, - "apikey.ApiKeyType": { + "models.ApiKeyType": { "type": "string", "enum": [ "client", - "project", - "workspace" + "workspace", + "target", + "runner" ], "x-enum-varnames": [ "ApiKeyTypeClient", - "ApiKeyTypeProject", - "ApiKeyTypeWorkspace" + "ApiKeyTypeWorkspace", + "ApiKeyTypeTarget", + "ApiKeyTypeRunner" ] }, - "build.BuildState": { + "models.JobAction": { "type": "string", "enum": [ + "create", + "start", + "stop", + "restart", + "delete", + "force-delete", + "run", + "install-provider", + "uninstall-provider", + "update-provider" + ], + "x-enum-varnames": [ + "JobActionCreate", + "JobActionStart", + "JobActionStop", + "JobActionRestart", + "JobActionDelete", + "JobActionForceDelete", + "JobActionRun", + "JobActionInstallProvider", + "JobActionUninstallProvider", + "JobActionUpdateProvider" + ] + }, + "models.ResourceStateName": { + "type": "string", + "enum": [ + "undefined", "pending-run", "running", + "run-successful", + "pending-create", + "creating", + "pending-start", + "starting", + "started", + "pending-stop", + "stopping", + "stopped", + "pending-restart", "error", - "success", - "published", + "unresponsive", "pending-delete", "pending-forced-delete", - "deleting" + "deleting", + "deleted" ], "x-enum-varnames": [ - "BuildStatePendingRun", - "BuildStateRunning", - "BuildStateError", - "BuildStateSuccess", - "BuildStatePublished", - "BuildStatePendingDelete", - "BuildStatePendingForcedDelete", - "BuildStateDeleting" + "ResourceStateNameUndefined", + "ResourceStateNamePendingRun", + "ResourceStateNameRunning", + "ResourceStateNameRunSuccessful", + "ResourceStateNamePendingCreate", + "ResourceStateNameCreating", + "ResourceStateNamePendingStart", + "ResourceStateNameStarting", + "ResourceStateNameStarted", + "ResourceStateNamePendingStop", + "ResourceStateNameStopping", + "ResourceStateNameStopped", + "ResourceStateNamePendingRestart", + "ResourceStateNameError", + "ResourceStateNameUnresponsive", + "ResourceStateNamePendingDelete", + "ResourceStateNamePendingForcedDelete", + "ResourceStateNameDeleting", + "ResourceStateNameDeleted" ] }, - "provider.ProviderInfo": { - "type": "object", - "required": [ - "name", - "version" - ], - "properties": { - "label": { - "type": "string" - }, - "name": { - "type": "string" - }, - "version": { - "type": "string" - } - } - }, - "provider.ProviderTargetProperty": { - "type": "object", - "properties": { - "defaultValue": { - "description": "DefaultValue is converted into the appropriate type based on the Type\nIf the property is a FilePath, the DefaultValue is a path to a directory", - "type": "string" - }, - "description": { - "description": "Brief description of the property", - "type": "string" - }, - "disabledPredicate": { - "description": "A regex string matched with the name of the target to determine if the property should be disabled\nIf the regex matches the target name, the property will be disabled\nE.g. \"^local$\" will disable the property for the local target", - "type": "string" - }, - "inputMasked": { - "type": "boolean" - }, - "options": { - "description": "Options is only used if the Type is ProviderTargetPropertyTypeOption", - "type": "array", - "items": { - "type": "string" - } - }, - "suggestions": { - "description": "Suggestions is an optional list of auto-complete values to assist the user while filling the field", - "type": "array", - "items": { - "type": "string" - } - }, - "type": { - "$ref": "#/definitions/provider.ProviderTargetPropertyType" - } - } - }, - "provider.ProviderTargetPropertyType": { + "models.TargetConfigPropertyType": { "type": "string", "enum": [ "string", @@ -5302,12 +6239,12 @@ "file-path" ], "x-enum-varnames": [ - "ProviderTargetPropertyTypeString", - "ProviderTargetPropertyTypeOption", - "ProviderTargetPropertyTypeBoolean", - "ProviderTargetPropertyTypeInt", - "ProviderTargetPropertyTypeFloat", - "ProviderTargetPropertyTypeFilePath" + "TargetConfigPropertyTypeString", + "TargetConfigPropertyTypeOption", + "TargetConfigPropertyTypeBoolean", + "TargetConfigPropertyTypeInt", + "TargetConfigPropertyTypeFloat", + "TargetConfigPropertyTypeFilePath" ] } }, diff --git a/pkg/api/docs/swagger.yaml b/pkg/api/docs/swagger.yaml index 61df4a4a14..7df6a4833f 100644 --- a/pkg/api/docs/swagger.yaml +++ b/pkg/api/docs/swagger.yaml @@ -1,20 +1,26 @@ basePath: / definitions: - ApiKey: + ApiKeyViewDTO: properties: - keyHash: - type: string + current: + type: boolean name: - description: Project or client name type: string type: - $ref: '#/definitions/apikey.ApiKeyType' + $ref: '#/definitions/models.ApiKeyType' required: - - keyHash + - current - name - type type: object - Build: + BuildConfig: + properties: + cachedBuild: + $ref: '#/definitions/CachedBuild' + devcontainer: + $ref: '#/definitions/DevcontainerConfig' + type: object + BuildDTO: properties: buildConfig: $ref: '#/definitions/BuildConfig' @@ -30,12 +36,16 @@ definitions: type: string image: type: string + lastJob: + $ref: '#/definitions/Job' + lastJobId: + type: string prebuildId: type: string repository: $ref: '#/definitions/GitRepository' state: - $ref: '#/definitions/build.BuildState' + $ref: '#/definitions/ResourceState' updatedAt: type: string user: @@ -45,18 +55,10 @@ definitions: - createdAt - envVars - id - - prebuildId - repository - state - updatedAt type: object - BuildConfig: - properties: - cachedBuild: - $ref: '#/definitions/CachedBuild' - devcontainer: - $ref: '#/definitions/DevcontainerConfig' - type: object CachedBuild: properties: image: @@ -159,12 +161,12 @@ definitions: type: object prebuildId: type: string - projectConfigName: + workspaceTemplateName: type: string required: - branch - envVars - - projectConfigName + - workspaceTemplateName type: object CreatePrebuildDTO: properties: @@ -183,30 +185,65 @@ definitions: required: - retention type: object - CreateProjectConfigDTO: + CreateRunnerDTO: properties: - buildConfig: - $ref: '#/definitions/BuildConfig' - envVars: - additionalProperties: - type: string - type: object - gitProviderConfigId: + id: type: string - image: + name: + type: string + required: + - id + - name + type: object + CreateRunnerResultDTO: + properties: + apiKey: + type: string + id: type: string + metadata: + $ref: '#/definitions/RunnerMetadata' name: type: string - repositoryUrl: + required: + - apiKey + - id + - name + type: object + CreateSessionRequest: + properties: + sessionId: type: string - user: + required: + - sessionId + type: object + CreateTargetConfigDTO: + properties: + name: + type: string + options: type: string + providerInfo: + $ref: '#/definitions/ProviderInfo' required: - - envVars - name - - repositoryUrl + - options + - providerInfo + type: object + CreateTargetDTO: + properties: + id: + type: string + name: + type: string + targetConfigId: + type: string + required: + - id + - name + - targetConfigId type: object - CreateProjectDTO: + CreateWorkspaceDTO: properties: buildConfig: $ref: '#/definitions/BuildConfig' @@ -216,63 +253,59 @@ definitions: type: object gitProviderConfigId: type: string + id: + type: string image: type: string + labels: + additionalProperties: + type: string + type: object name: type: string source: - $ref: '#/definitions/CreateProjectSourceDTO' + $ref: '#/definitions/CreateWorkspaceSourceDTO' + targetId: + type: string user: type: string required: - envVars + - id + - labels - name - source + - targetId type: object - CreateProjectSourceDTO: + CreateWorkspaceSourceDTO: properties: repository: $ref: '#/definitions/GitRepository' required: - repository type: object - CreateProviderTargetDTO: - properties: - name: - type: string - options: - type: string - providerInfo: - $ref: '#/definitions/provider.ProviderInfo' - required: - - name - - options - - providerInfo - type: object - CreateSessionRequest: + CreateWorkspaceTemplateDTO: properties: - sessionId: + buildConfig: + $ref: '#/definitions/BuildConfig' + envVars: + additionalProperties: + type: string + type: object + gitProviderConfigId: type: string - required: - - sessionId - type: object - CreateWorkspaceDTO: - properties: - id: + image: type: string name: type: string - projects: - items: - $ref: '#/definitions/CreateProjectDTO' - type: array - target: + repositoryUrl: + type: string + user: type: string required: - - id + - envVars - name - - projects - - target + - repositoryUrl type: object DevcontainerConfig: properties: @@ -281,6 +314,16 @@ definitions: required: - filePath type: object + EnvironmentVariable: + properties: + key: + type: string + value: + type: string + required: + - key + - value + type: object ExecuteRequest: properties: command: @@ -610,18 +653,50 @@ definitions: - name - username type: object - InstallProviderRequest: + Job: properties: - downloadUrls: - additionalProperties: - type: string - type: object - name: + action: + $ref: '#/definitions/models.JobAction' + createdAt: + type: string + error: + type: string + id: + type: string + metadata: + description: JSON encoded metadata + type: string + resourceId: + type: string + resourceType: + $ref: '#/definitions/ResourceType' + runnerId: + type: string + state: + $ref: '#/definitions/JobState' + updatedAt: type: string required: - - downloadUrls - - name + - action + - createdAt + - id + - resourceId + - resourceType + - state + - updatedAt type: object + JobState: + enum: + - pending + - running + - error + - success + type: string + x-enum-varnames: + - JobStatePending + - JobStateRunning + - JobStateError + - JobStateSuccess ListBranchResponse: properties: branches: @@ -781,7 +856,6 @@ definitions: type: array required: - branch - - commitInterval - id - retention - triggerFiles @@ -794,161 +868,57 @@ definitions: type: integer id: type: string - projectConfigName: - type: string retention: type: integer triggerFiles: items: type: string type: array + workspaceTemplateName: + type: string required: - branch - id - - projectConfigName - retention + - workspaceTemplateName type: object - ProfileData: - properties: - envVars: - additionalProperties: - type: string - type: object - required: - - envVars - type: object - Project: + ProviderDTO: properties: - buildConfig: - $ref: '#/definitions/BuildConfig' - envVars: - additionalProperties: - type: string - type: object - gitProviderConfigId: - type: string - image: - type: string - name: - type: string - repository: - $ref: '#/definitions/GitRepository' - state: - $ref: '#/definitions/ProjectState' - target: - type: string - user: - type: string - workspaceId: + label: type: string - required: - - envVars - - image - - name - - repository - - target - - user - - workspaceId - type: object - ProjectConfig: - properties: - buildConfig: - $ref: '#/definitions/BuildConfig' - default: + latest: type: boolean - envVars: - additionalProperties: - type: string - type: object - gitProviderConfigId: - type: string - image: - type: string name: type: string - prebuilds: - items: - $ref: '#/definitions/PrebuildConfig' - type: array - repositoryUrl: - type: string - user: + version: type: string required: - - default - - envVars - - image + - latest - name - - repositoryUrl - - user - type: object - ProjectDirResponse: - properties: - dir: - type: string + - version type: object - ProjectInfo: + ProviderInfo: properties: - created: - type: string - isRunning: + agentlessTarget: type: boolean - name: - type: string - providerMetadata: - type: string - workspaceId: - type: string - required: - - created - - isRunning - - name - - workspaceId - type: object - ProjectState: - properties: - gitStatus: - $ref: '#/definitions/GitStatus' - updatedAt: - type: string - uptime: - type: integer - required: - - updatedAt - - uptime - type: object - Provider: - properties: label: type: string name: type: string - version: + runnerId: type: string - required: - - name - - version - type: object - ProviderTarget: - properties: - isDefault: - type: boolean - name: + runnerName: type: string - options: - description: JSON encoded map of options + targetConfigManifest: + $ref: '#/definitions/TargetConfigManifest' + version: type: string - providerInfo: - $ref: '#/definitions/provider.ProviderInfo' required: - - isDefault - name - - options - - providerInfo - type: object - ProviderTargetManifest: - additionalProperties: - $ref: '#/definitions/provider.ProviderTargetProperty' + - runnerId + - runnerName + - targetConfigManifest + - version type: object ReplaceRequest: properties: @@ -981,9 +951,68 @@ definitions: required: - url type: object - Sample: + ResourceState: properties: - description: + error: + type: string + name: + $ref: '#/definitions/models.ResourceStateName' + updatedAt: + type: string + required: + - name + - updatedAt + type: object + ResourceType: + enum: + - workspace + - target + - build + - runner + type: string + x-enum-varnames: + - ResourceTypeWorkspace + - ResourceTypeTarget + - ResourceTypeBuild + - ResourceTypeRunner + RunnerDTO: + properties: + id: + type: string + metadata: + $ref: '#/definitions/RunnerMetadata' + name: + type: string + state: + $ref: '#/definitions/ResourceState' + required: + - id + - name + - state + type: object + RunnerMetadata: + properties: + providers: + items: + $ref: '#/definitions/ProviderInfo' + type: array + runnerId: + type: string + runningJobs: + type: integer + updatedAt: + type: string + uptime: + type: integer + required: + - providers + - runnerId + - updatedAt + - uptime + type: object + Sample: + properties: + description: type: string gitUrl: type: string @@ -1015,9 +1044,9 @@ definitions: type: string builderRegistryServer: type: string - defaultProjectImage: + defaultWorkspaceImage: type: string - defaultProjectUser: + defaultWorkspaceUser: type: string frps: $ref: '#/definitions/FRPSConfig' @@ -1029,10 +1058,10 @@ definitions: type: string localBuilderRegistryPort: type: integer + localRunnerDisabled: + type: boolean logFile: $ref: '#/definitions/LogFileConfig' - providersDir: - type: string registryUrl: type: string samplesIndexUrl: @@ -1044,14 +1073,13 @@ definitions: - binariesPath - builderImage - builderRegistryServer - - defaultProjectImage - - defaultProjectUser + - defaultWorkspaceImage + - defaultWorkspaceUser - headscalePort - id - localBuilderRegistryImage - localBuilderRegistryPort - logFile - - providersDir - registryUrl - serverDownloadUrl type: object @@ -1107,15 +1135,6 @@ definitions: - providerId - token type: object - SetProjectState: - properties: - gitStatus: - $ref: '#/definitions/GitStatus' - uptime: - type: integer - required: - - uptime - type: object SigningMethod: enum: - ssh @@ -1144,101 +1163,68 @@ definitions: - Renamed - Copied - UpdatedButUnmerged - Workspace: + Target: properties: + default: + type: boolean + envVars: + additionalProperties: + type: string + type: object id: type: string + lastJob: + $ref: '#/definitions/Job' + lastJobId: + type: string + metadata: + $ref: '#/definitions/TargetMetadata' name: type: string - projects: + providerMetadata: + type: string + targetConfig: + $ref: '#/definitions/TargetConfig' + targetConfigId: + type: string + workspaces: items: - $ref: '#/definitions/Project' + $ref: '#/definitions/Workspace' type: array - target: - type: string required: + - default + - envVars - id - name - - projects - - target + - targetConfig + - targetConfigId + - workspaces type: object - WorkspaceDTO: + TargetConfig: properties: + deleted: + type: boolean id: type: string - info: - $ref: '#/definitions/WorkspaceInfo' name: type: string - projects: - items: - $ref: '#/definitions/Project' - type: array - target: + options: + description: JSON encoded map of options type: string + providerInfo: + $ref: '#/definitions/ProviderInfo' required: + - deleted - id - name - - projects - - target - type: object - WorkspaceInfo: - properties: - name: - type: string - projects: - items: - $ref: '#/definitions/ProjectInfo' - type: array - providerMetadata: - type: string - required: - - name - - projects + - options + - providerInfo type: object - apikey.ApiKeyType: - enum: - - client - - project - - workspace - type: string - x-enum-varnames: - - ApiKeyTypeClient - - ApiKeyTypeProject - - ApiKeyTypeWorkspace - build.BuildState: - enum: - - pending-run - - running - - error - - success - - published - - pending-delete - - pending-forced-delete - - deleting - type: string - x-enum-varnames: - - BuildStatePendingRun - - BuildStateRunning - - BuildStateError - - BuildStateSuccess - - BuildStatePublished - - BuildStatePendingDelete - - BuildStatePendingForcedDelete - - BuildStateDeleting - provider.ProviderInfo: - properties: - label: - type: string - name: - type: string - version: - type: string - required: - - name - - version + TargetConfigManifest: + additionalProperties: + $ref: '#/definitions/TargetConfigProperty' type: object - provider.ProviderTargetProperty: + TargetConfigProperty: properties: defaultValue: description: |- @@ -1250,14 +1236,14 @@ definitions: type: string disabledPredicate: description: |- - A regex string matched with the name of the target to determine if the property should be disabled - If the regex matches the target name, the property will be disabled + A regex string matched with the name of the target config to determine if the property should be disabled + If the regex matches the target config name, the property will be disabled E.g. "^local$" will disable the property for the local target type: string inputMasked: type: boolean options: - description: Options is only used if the Type is ProviderTargetPropertyTypeOption + description: Options is only used if the Type is TargetConfigPropertyTypeOption items: type: string type: array @@ -1268,159 +1254,503 @@ definitions: type: string type: array type: - $ref: '#/definitions/provider.ProviderTargetPropertyType' + $ref: '#/definitions/models.TargetConfigPropertyType' type: object - provider.ProviderTargetPropertyType: - enum: - - string - - option - - boolean - - int - - float - - file-path - type: string - x-enum-varnames: - - ProviderTargetPropertyTypeString - - ProviderTargetPropertyTypeOption - - ProviderTargetPropertyTypeBoolean - - ProviderTargetPropertyTypeInt - - ProviderTargetPropertyTypeFloat - - ProviderTargetPropertyTypeFilePath -host: localhost:3986 -info: - contact: {} - description: Daytona Server API - title: Daytona Server API - version: v0.0.0-dev -paths: - /apikey: - get: - description: List API keys - operationId: ListClientApiKeys - produces: - - application/json - responses: - "200": - description: OK - schema: - items: - $ref: '#/definitions/ApiKey' - type: array - summary: List API keys - tags: - - apiKey - /apikey/{apiKeyName}: - delete: - description: Revoke API key - operationId: RevokeApiKey - parameters: - - description: API key name - in: path - name: apiKeyName - required: true + TargetDTO: + properties: + default: + type: boolean + envVars: + additionalProperties: + type: string + type: object + id: type: string - responses: - "200": - description: OK - summary: Revoke API key - tags: - - apiKey - post: - description: Generate an API key - operationId: GenerateApiKey - parameters: - - description: API key name - in: path - name: apiKeyName - required: true + lastJob: + $ref: '#/definitions/Job' + lastJobId: type: string - produces: - - text/plain - responses: - "200": - description: OK - schema: - type: string - summary: Generate an API key - tags: - - apiKey - /build: - delete: - description: Delete ALL builds - operationId: DeleteAllBuilds - parameters: - - description: Force - in: query - name: force - type: boolean - responses: - "204": - description: No Content - summary: Delete ALL builds - tags: - - build - get: - description: List builds - operationId: ListBuilds - produces: - - application/json - responses: - "200": - description: OK - schema: - items: - $ref: '#/definitions/Build' - type: array - summary: List builds - tags: - - build - post: - consumes: - - application/json - description: Create a build - operationId: CreateBuild - parameters: - - description: Create Build DTO - in: body - name: createBuildDto - required: true - schema: - $ref: '#/definitions/CreateBuildDTO' - responses: - "201": - description: Created - schema: - type: string - summary: Create a build - tags: - - build - /build/{buildId}: - delete: - description: Delete build - operationId: DeleteBuild - parameters: - - description: Build ID - in: path - name: buildId - required: true + metadata: + $ref: '#/definitions/TargetMetadata' + name: type: string - - description: Force - in: query - name: force - type: boolean - responses: - "204": - description: No Content - summary: Delete build - tags: - - build - get: - consumes: - - application/json - description: Get build data - operationId: GetBuild - parameters: - - description: Build ID + providerMetadata: + type: string + state: + $ref: '#/definitions/ResourceState' + targetConfig: + $ref: '#/definitions/TargetConfig' + targetConfigId: + type: string + workspaces: + items: + $ref: '#/definitions/Workspace' + type: array + required: + - default + - envVars + - id + - name + - state + - targetConfig + - targetConfigId + - workspaces + type: object + TargetMetadata: + properties: + targetId: + type: string + updatedAt: + type: string + uptime: + type: integer + required: + - targetId + - updatedAt + - uptime + type: object + UpdateJobState: + properties: + errorMessage: + type: string + state: + $ref: '#/definitions/JobState' + required: + - state + type: object + UpdateRunnerMetadataDTO: + properties: + providers: + items: + $ref: '#/definitions/ProviderInfo' + type: array + runningJobs: + type: integer + uptime: + type: integer + required: + - providers + - uptime + type: object + UpdateTargetMetadataDTO: + properties: + uptime: + type: integer + required: + - uptime + type: object + UpdateTargetProviderMetadataDTO: + properties: + metadata: + type: string + required: + - metadata + type: object + UpdateWorkspaceMetadataDTO: + properties: + gitStatus: + $ref: '#/definitions/GitStatus' + uptime: + type: integer + required: + - uptime + type: object + UpdateWorkspaceProviderMetadataDTO: + properties: + metadata: + type: string + required: + - metadata + type: object + Workspace: + properties: + apiKey: + type: string + buildConfig: + $ref: '#/definitions/BuildConfig' + envVars: + additionalProperties: + type: string + type: object + gitProviderConfigId: + type: string + id: + type: string + image: + type: string + labels: + additionalProperties: + type: string + type: object + lastJob: + $ref: '#/definitions/Job' + lastJobId: + type: string + metadata: + $ref: '#/definitions/WorkspaceMetadata' + name: + type: string + providerMetadata: + type: string + repository: + $ref: '#/definitions/GitRepository' + target: + $ref: '#/definitions/Target' + targetId: + type: string + user: + type: string + required: + - apiKey + - envVars + - id + - image + - labels + - name + - repository + - target + - targetId + - user + type: object + WorkspaceDTO: + properties: + apiKey: + type: string + buildConfig: + $ref: '#/definitions/BuildConfig' + envVars: + additionalProperties: + type: string + type: object + gitProviderConfigId: + type: string + id: + type: string + image: + type: string + labels: + additionalProperties: + type: string + type: object + lastJob: + $ref: '#/definitions/Job' + lastJobId: + type: string + metadata: + $ref: '#/definitions/WorkspaceMetadata' + name: + type: string + providerMetadata: + type: string + repository: + $ref: '#/definitions/GitRepository' + state: + $ref: '#/definitions/ResourceState' + target: + $ref: '#/definitions/Target' + targetId: + type: string + user: + type: string + required: + - apiKey + - envVars + - id + - image + - labels + - name + - repository + - state + - target + - targetId + - user + type: object + WorkspaceDirResponse: + properties: + dir: + type: string + type: object + WorkspaceMetadata: + properties: + gitStatus: + $ref: '#/definitions/GitStatus' + updatedAt: + type: string + uptime: + type: integer + workspaceId: + type: string + required: + - updatedAt + - uptime + - workspaceId + type: object + WorkspaceTemplate: + properties: + buildConfig: + $ref: '#/definitions/BuildConfig' + default: + type: boolean + envVars: + additionalProperties: + type: string + type: object + gitProviderConfigId: + type: string + image: + type: string + labels: + additionalProperties: + type: string + type: object + name: + type: string + prebuilds: + items: + $ref: '#/definitions/PrebuildConfig' + type: array + repositoryUrl: + type: string + user: + type: string + required: + - default + - envVars + - image + - labels + - name + - repositoryUrl + - user + type: object + models.ApiKeyType: + enum: + - client + - workspace + - target + - runner + type: string + x-enum-varnames: + - ApiKeyTypeClient + - ApiKeyTypeWorkspace + - ApiKeyTypeTarget + - ApiKeyTypeRunner + models.JobAction: + enum: + - create + - start + - stop + - restart + - delete + - force-delete + - run + - install-provider + - uninstall-provider + - update-provider + type: string + x-enum-varnames: + - JobActionCreate + - JobActionStart + - JobActionStop + - JobActionRestart + - JobActionDelete + - JobActionForceDelete + - JobActionRun + - JobActionInstallProvider + - JobActionUninstallProvider + - JobActionUpdateProvider + models.ResourceStateName: + enum: + - undefined + - pending-run + - running + - run-successful + - pending-create + - creating + - pending-start + - starting + - started + - pending-stop + - stopping + - stopped + - pending-restart + - error + - unresponsive + - pending-delete + - pending-forced-delete + - deleting + - deleted + type: string + x-enum-varnames: + - ResourceStateNameUndefined + - ResourceStateNamePendingRun + - ResourceStateNameRunning + - ResourceStateNameRunSuccessful + - ResourceStateNamePendingCreate + - ResourceStateNameCreating + - ResourceStateNamePendingStart + - ResourceStateNameStarting + - ResourceStateNameStarted + - ResourceStateNamePendingStop + - ResourceStateNameStopping + - ResourceStateNameStopped + - ResourceStateNamePendingRestart + - ResourceStateNameError + - ResourceStateNameUnresponsive + - ResourceStateNamePendingDelete + - ResourceStateNamePendingForcedDelete + - ResourceStateNameDeleting + - ResourceStateNameDeleted + models.TargetConfigPropertyType: + enum: + - string + - option + - boolean + - int + - float + - file-path + type: string + x-enum-varnames: + - TargetConfigPropertyTypeString + - TargetConfigPropertyTypeOption + - TargetConfigPropertyTypeBoolean + - TargetConfigPropertyTypeInt + - TargetConfigPropertyTypeFloat + - TargetConfigPropertyTypeFilePath +host: localhost:3986 +info: + contact: {} + description: Daytona Server API + title: Daytona Server API + version: v0.0.0-dev +paths: + /apikey: + get: + description: List API keys + operationId: ListClientApiKeys + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/ApiKeyViewDTO' + type: array + summary: List API keys + tags: + - apiKey + /apikey/{apiKeyName}: + delete: + description: Delete API key + operationId: DeleteApiKey + parameters: + - description: API key name + in: path + name: apiKeyName + required: true + type: string + responses: + "200": + description: OK + summary: Delete API key + tags: + - apiKey + post: + description: Create an API key + operationId: CreateApiKey + parameters: + - description: API key name + in: path + name: apiKeyName + required: true + type: string + produces: + - text/plain + responses: + "200": + description: OK + schema: + type: string + summary: Create an API key + tags: + - apiKey + /build: + delete: + description: Delete ALL builds + operationId: DeleteAllBuilds + parameters: + - description: Force + in: query + name: force + type: boolean + responses: + "204": + description: No Content + summary: Delete ALL builds + tags: + - build + get: + description: List builds + operationId: ListBuilds + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/BuildDTO' + type: array + summary: List builds + tags: + - build + post: + consumes: + - application/json + description: Create a build + operationId: CreateBuild + parameters: + - description: Create Build DTO + in: body + name: createBuildDto + required: true + schema: + $ref: '#/definitions/CreateBuildDTO' + responses: + "201": + description: Created + schema: + type: string + summary: Create a build + tags: + - build + /build/{buildId}: + delete: + description: Delete build + operationId: DeleteBuild + parameters: + - description: Build ID + in: path + name: buildId + required: true + type: string + - description: Force + in: query + name: force + type: boolean + responses: + "204": + description: No Content + summary: Delete build + tags: + - build + get: + consumes: + - application/json + description: Find build + operationId: FindBuild + parameters: + - description: Build ID in: path name: buildId required: true @@ -1429,8 +1759,8 @@ paths: "200": description: OK schema: - $ref: '#/definitions/Build' - summary: Get build data + $ref: '#/definitions/BuildDTO' + summary: Find build tags: - build /build/prebuild/{prebuildId}: @@ -1453,10 +1783,16 @@ paths: summary: Delete builds tags: - build - /container-registry: + /build/successful/{repoUrl}: get: - description: List container registries - operationId: ListContainerRegistries + description: List successful builds for Git repository + operationId: ListSuccessfulBuilds + parameters: + - description: Repository URL + in: path + name: repoUrl + required: true + type: string produces: - application/json responses: @@ -1464,67 +1800,85 @@ paths: description: OK schema: items: - $ref: '#/definitions/ContainerRegistry' + $ref: '#/definitions/BuildDTO' type: array - summary: List container registries + summary: List successful builds for Git repository tags: - - container-registry + - build /container-registry/{server}: - delete: - description: Remove a container registry credentials - operationId: RemoveContainerRegistry + get: + description: Find container registry + operationId: FindContainerRegistry parameters: - - description: Container Registry server name + - description: Container registry server in: path name: server required: true type: string + - description: Workspace ID or Name + in: query + name: workspaceId + type: string + produces: + - application/json responses: - "204": - description: No Content - summary: Remove a container registry credentials + "200": + description: OK + schema: + $ref: '#/definitions/ContainerRegistry' + summary: Find container registry tags: - - container-registry + - container registry + /env: get: - description: Get container registry credentials - operationId: GetContainerRegistry - parameters: - - description: Container Registry server name - in: path - name: server - required: true - type: string + description: List environment variables + operationId: ListEnvironmentVariables produces: - application/json responses: "200": description: OK schema: - $ref: '#/definitions/ContainerRegistry' - summary: Get container registry credentials + items: + $ref: '#/definitions/EnvironmentVariable' + type: array + summary: List environment variables tags: - - container-registry + - envVar put: - description: Set container registry credentials - operationId: SetContainerRegistry + consumes: + - application/json + description: Save environment variable + operationId: SaveEnvironmentVariable parameters: - - description: Container Registry server name - in: path - name: server - required: true - type: string - - description: Container Registry credentials to set + - description: Environment Variable in: body - name: containerRegistry + name: environmentVariable required: true schema: - $ref: '#/definitions/ContainerRegistry' + $ref: '#/definitions/EnvironmentVariable' responses: "201": description: Created - summary: Set container registry credentials + summary: Save environment variable + tags: + - envVar + /env/{key}: + delete: + description: Delete environment variable + operationId: DeleteEnvironmentVariable + parameters: + - description: Environment Variable Key + in: path + name: key + required: true + type: string + responses: + "204": + description: No Content + summary: Delete environment variable tags: - - container-registry + - envVar /gitprovider: get: description: List Git providers @@ -1542,8 +1896,8 @@ paths: tags: - gitProvider put: - description: Set Git provider - operationId: SetGitProvider + description: Save Git provider + operationId: SaveGitProvider parameters: - description: Git provider in: body @@ -1556,13 +1910,13 @@ paths: responses: "200": description: OK - summary: Set Git provider + summary: Save Git provider tags: - gitProvider /gitprovider/{gitProviderId}: delete: - description: Remove Git provider - operationId: RemoveGitProvider + description: Delete Git provider + operationId: DeleteGitProvider parameters: - description: Git provider in: path @@ -1574,12 +1928,12 @@ paths: responses: "200": description: OK - summary: Remove Git provider + summary: Delete Git provider tags: - gitProvider get: - description: Get Git provider - operationId: GetGitProvider + description: Find Git provider + operationId: FindGitProvider parameters: - description: ID in: path @@ -1593,7 +1947,7 @@ paths: description: OK schema: $ref: '#/definitions/GitProvider' - summary: Get Git provider + summary: Find Git provider tags: - gitProvider /gitprovider/{gitProviderId}/{namespaceId}/{repositoryId}/branches: @@ -1735,20 +2089,248 @@ paths: "200": description: OK schema: - items: - $ref: '#/definitions/GitNamespace' - type: array - summary: Get Git namespaces + items: + $ref: '#/definitions/GitNamespace' + type: array + summary: Get Git namespaces + tags: + - gitProvider + /gitprovider/{gitProviderId}/user: + get: + description: Get Git context + operationId: GetGitUser + parameters: + - description: Git Provider Id + in: path + name: gitProviderId + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/GitUser' + summary: Get Git context + tags: + - gitProvider + /gitprovider/context: + post: + description: Get Git context + operationId: GetGitContext + parameters: + - description: Get repository context + in: body + name: repository + required: true + schema: + $ref: '#/definitions/GetRepositoryContext' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/GitRepository' + summary: Get Git context + tags: + - gitProvider + /gitprovider/context/url: + post: + description: Get URL from Git repository + operationId: GetUrlFromRepository + parameters: + - description: Git repository + in: body + name: repository + required: true + schema: + $ref: '#/definitions/GitRepository' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/RepositoryUrl' + summary: Get URL from Git repository + tags: + - gitProvider + /gitprovider/for-url/{url}: + get: + description: List Git providers for url + operationId: ListGitProvidersForUrl + parameters: + - description: Url + in: path + name: url + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/GitProvider' + type: array + summary: List Git providers for url + tags: + - gitProvider + /gitprovider/id-for-url/{url}: + get: + description: Find Git provider ID + operationId: FindGitProviderIdForUrl + parameters: + - description: Url + in: path + name: url + required: true + type: string + produces: + - text/plain + responses: + "200": + description: OK + schema: + type: string + summary: Find Git provider ID + tags: + - gitProvider + /health: + get: + description: Health check + operationId: HealthCheck + produces: + - application/json + responses: + "200": + description: OK + schema: + additionalProperties: + type: string + type: object + summary: Health check + /job: + get: + description: List jobs + operationId: ListJobs + parameters: + - collectionFormat: multi + description: Job States + in: query + items: + type: string + name: states + type: array + - collectionFormat: multi + description: Job Actions + in: query + items: + type: string + name: actions + type: array + - description: Resource ID + in: query + name: resourceId + type: string + - description: Resource Type + in: query + name: resourceType + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/Job' + type: array + summary: List jobs + tags: + - job + /runner: + get: + description: List runners + operationId: ListRunners + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/RunnerDTO' + type: array + summary: List runners + tags: + - runner + post: + description: Create a runner + operationId: CreateRunner + parameters: + - description: Runner + in: body + name: runner + required: true + schema: + $ref: '#/definitions/CreateRunnerDTO' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/CreateRunnerResultDTO' + summary: Create a runner + tags: + - runner + /runner/{runnerId}: + delete: + description: Delete runner + operationId: DeleteRunner + parameters: + - description: Runner ID + in: path + name: runnerId + required: true + type: string + responses: + "200": + description: OK + summary: Delete runner + tags: + - runner + get: + description: Find a runner + operationId: FindRunner + parameters: + - description: Runner ID + in: path + name: runnerId + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/RunnerDTO' + summary: Find a runner tags: - - gitProvider - /gitprovider/{gitProviderId}/user: + - runner + /runner/{runnerId}/jobs: get: - description: Get Git context - operationId: GetGitUser + description: List runner jobs + operationId: ListRunnerJobs parameters: - - description: Git Provider Id + - description: Runner ID in: path - name: gitProviderId + name: runnerId required: true type: string produces: @@ -1757,60 +2339,71 @@ paths: "200": description: OK schema: - $ref: '#/definitions/GitUser' - summary: Get Git context + items: + $ref: '#/definitions/Job' + type: array + summary: List runner jobs tags: - - gitProvider - /gitprovider/context: + - runner + /runner/{runnerId}/jobs/{jobId}/state: post: - description: Get Git context - operationId: GetGitContext + description: Update job state + operationId: UpdateJobState parameters: - - description: Get repository context + - description: Runner ID + in: path + name: runnerId + required: true + type: string + - description: Job ID + in: path + name: jobId + required: true + type: string + - description: Update job state in: body - name: repository + name: updateJobState required: true schema: - $ref: '#/definitions/GetRepositoryContext' + $ref: '#/definitions/UpdateJobState' produces: - application/json responses: "200": description: OK - schema: - $ref: '#/definitions/GitRepository' - summary: Get Git context + summary: Update job state tags: - - gitProvider - /gitprovider/context/url: + - runner + /runner/{runnerId}/metadata: post: - description: Get URL from Git repository - operationId: GetUrlFromRepository + description: Update runner metadata + operationId: UpdateRunnerMetadata parameters: - - description: Git repository + - description: Runner ID + in: path + name: runnerId + required: true + type: string + - description: Runner Metadata in: body - name: repository + name: runnerMetadata required: true schema: - $ref: '#/definitions/GitRepository' - produces: - - application/json + $ref: '#/definitions/UpdateRunnerMetadataDTO' responses: "200": description: OK - schema: - $ref: '#/definitions/RepositoryUrl' - summary: Get URL from Git repository + summary: Update runner metadata tags: - - gitProvider - /gitprovider/for-url/{url}: + - runner + /runner/{runnerId}/provider: get: - description: List Git providers for url - operationId: ListGitProvidersForUrl + description: Get runner providers + operationId: GetRunnerProviders parameters: - - description: Url + - description: Runner ID in: path - name: url + name: runnerId required: true type: string produces: @@ -1820,90 +2413,175 @@ paths: description: OK schema: items: - $ref: '#/definitions/GitProvider' + $ref: '#/definitions/ProviderInfo' type: array - summary: List Git providers for url + summary: Get runner providers tags: - - gitProvider - /gitprovider/id-for-url/{url}: - get: - description: Get Git provider ID - operationId: GetGitProviderIdForUrl + - provider + /runner/{runnerId}/provider/{providerName}/install: + post: + description: Install provider + operationId: InstallProvider parameters: - - description: Url + - description: Runner ID in: path - name: url + name: runnerId + required: true + type: string + - description: Provider name + in: path + name: providerName + required: true + type: string + - description: Provider version - defaults to 'latest' + in: query + name: providerVersion + type: string + responses: + "200": + description: OK + summary: Install provider + tags: + - provider + /runner/{runnerId}/provider/{providerName}/uninstall: + post: + description: Uninstall provider + operationId: UninstallProvider + parameters: + - description: Runner ID + in: path + name: runnerId + required: true + type: string + - description: Provider name + in: path + name: providerName + required: true + type: string + responses: + "200": + description: OK + summary: Uninstall provider + tags: + - provider + /runner/{runnerId}/provider/{providerName}/update: + post: + description: Update provider + operationId: UpdateProvider + parameters: + - description: Runner ID + in: path + name: runnerId required: true type: string + - description: Provider name + in: path + name: providerName + required: true + type: string + - description: Provider version - defaults to 'latest' + in: query + name: providerVersion + type: string + responses: + "200": + description: OK + summary: Update provider + tags: + - provider + /runner/provider: + get: + description: List providers + operationId: ListProviders + parameters: + - description: Runner ID + in: query + name: runnerId + type: string produces: - - text/plain + - application/json responses: "200": description: OK schema: - type: string - summary: Get Git provider ID + items: + $ref: '#/definitions/ProviderInfo' + type: array + summary: List providers tags: - - gitProvider - /health: + - provider + /runner/provider/for-install: get: - description: Health check - operationId: HealthCheck + description: List providers available for installation + operationId: ListProvidersForInstall produces: - application/json responses: "200": description: OK schema: - additionalProperties: - type: string - type: object - summary: Health check - /profile: - delete: - description: Delete profile data - operationId: DeleteProfileData + items: + $ref: '#/definitions/ProviderDTO' + type: array + summary: List providers available for installation + tags: + - provider + /sample: + get: + description: List samples + operationId: ListSamples + produces: + - application/json responses: - "204": - description: No Content - summary: Delete profile data + "200": + description: OK + schema: + items: + $ref: '#/definitions/Sample' + type: array + summary: List samples tags: - - profile + - sample + /server/config: get: - consumes: + description: Get the server configuration + operationId: GetConfig + produces: - application/json - description: Get profile data - operationId: GetProfileData responses: "200": description: OK schema: - $ref: '#/definitions/ProfileData' - summary: Get profile data + $ref: '#/definitions/ServerConfig' + summary: Get the server configuration tags: - - profile + - server put: consumes: - application/json - description: Set profile data - operationId: SetProfileData + description: Save the server configuration + operationId: SaveConfig parameters: - - description: Profile data + - description: Server configuration in: body - name: profileData + name: config required: true schema: - $ref: '#/definitions/ProfileData' + $ref: '#/definitions/ServerConfig' + produces: + - application/json responses: - "201": - description: Created - summary: Set profile data + "200": + description: OK + schema: + $ref: '#/definitions/ServerConfig' + summary: Save the server configuration tags: - - profile - /project-config: + - server + /server/logs: get: - description: List project configs - operationId: ListProjectConfigs + description: Get server log files + operationId: GetServerLogFiles produces: - application/json responses: @@ -1911,130 +2589,133 @@ paths: description: OK schema: items: - $ref: '#/definitions/ProjectConfig' + type: string type: array - summary: List project configs + summary: Get server log files tags: - - project-config - put: - consumes: + - server + /server/network-key: + post: + description: Create a new authentication key + operationId: CreateNetworkKey + produces: - application/json - description: Set project config data - operationId: SetProjectConfig - parameters: - - description: Project config - in: body - name: projectConfig - required: true - schema: - $ref: '#/definitions/CreateProjectConfigDTO' responses: - "201": - description: Created - summary: Set project config data + "200": + description: OK + schema: + $ref: '#/definitions/NetworkKey' + summary: Create a new authentication key tags: - - project-config - /project-config/{configName}: - delete: - description: Delete project config data - operationId: DeleteProjectConfig + - server + /target: + get: + description: List targets + operationId: ListTargets parameters: - - description: Config name - in: path - name: configName - required: true - type: string - - description: Force + - description: Show target config options in: query - name: force + name: showOptions type: boolean + produces: + - application/json responses: - "204": - description: No Content - summary: Delete project config data + "200": + description: OK + schema: + items: + $ref: '#/definitions/TargetDTO' + type: array + summary: List targets tags: - - project-config - get: - consumes: - - application/json - description: Get project config data - operationId: GetProjectConfig + - target + post: + description: Create a target + operationId: CreateTarget parameters: - - description: Config name - in: path - name: configName + - description: Create target + in: body + name: target required: true - type: string + schema: + $ref: '#/definitions/CreateTargetDTO' + produces: + - application/json responses: "200": description: OK schema: - $ref: '#/definitions/ProjectConfig' - summary: Get project config data + $ref: '#/definitions/Target' + summary: Create a target tags: - - project-config - /project-config/{configName}/prebuild: + - target + /target-config: get: - consumes: - - application/json - description: List prebuilds for project config - operationId: ListPrebuildsForProjectConfig + description: List target configs + operationId: ListTargetConfigs parameters: - - description: Config name - in: path - name: configName - required: true - type: string + - description: Show target config options + in: query + name: showOptions + type: boolean + produces: + - application/json responses: "200": description: OK schema: items: - $ref: '#/definitions/PrebuildDTO' + $ref: '#/definitions/TargetConfig' type: array - summary: List prebuilds for project config + summary: List target configs tags: - - prebuild - put: - consumes: - - application/json - description: Set prebuild - operationId: SetPrebuild + - target-config + post: + description: Create a target config + operationId: CreateTargetConfig parameters: - - description: Config name - in: path - name: configName - required: true - type: string - - description: Prebuild + - description: Target config to create in: body - name: prebuild + name: targetConfig required: true schema: - $ref: '#/definitions/CreatePrebuildDTO' + $ref: '#/definitions/CreateTargetConfigDTO' + - description: Show target config options + in: query + name: showOptions + type: boolean responses: - "201": - description: Created + "200": + description: OK schema: - type: string - summary: Set prebuild + $ref: '#/definitions/TargetConfig' + summary: Create a target config tags: - - prebuild - /project-config/{configName}/prebuild/{prebuildId}: - delete: - consumes: - - application/json - description: Delete prebuild - operationId: DeletePrebuild + - target-config + /target-config/{configId}: + delete: + description: Delete a target config + operationId: DeleteTargetConfig parameters: - - description: Project config name + - description: Target Config Id in: path - name: configName + name: configId required: true type: string - - description: Prebuild ID + responses: + "204": + description: No Content + summary: Delete a target config + tags: + - target-config + /target/{targetId}: + delete: + description: Delete target + operationId: DeleteTarget + parameters: + - description: Target ID in: path - name: prebuildId + name: targetId required: true type: string - description: Force @@ -2042,231 +2723,223 @@ paths: name: force type: boolean responses: - "204": - description: No Content - summary: Delete prebuild + "200": + description: OK + summary: Delete target tags: - - prebuild + - target get: - consumes: - - application/json - description: Get prebuild - operationId: GetPrebuild + description: Find target + operationId: FindTarget parameters: - - description: Project config name - in: path - name: configName - required: true - type: string - - description: Prebuild ID + - description: Target ID or Name in: path - name: prebuildId + name: targetId required: true type: string + - description: Show target config options + in: query + name: showOptions + type: boolean + produces: + - application/json responses: "200": description: OK schema: - $ref: '#/definitions/PrebuildDTO' - summary: Get prebuild + $ref: '#/definitions/TargetDTO' + summary: Find target tags: - - prebuild - /project-config/{configName}/set-default: - patch: - description: Set project config to default - operationId: SetDefaultProjectConfig + - target + /target/{targetId}/handle-successful-creation: + post: + description: Handles successful creation of the target + operationId: HandleSuccessfulCreation parameters: - - description: Config name + - description: Target ID or name in: path - name: configName + name: targetId required: true type: string responses: "200": description: OK - summary: Set project config to default + summary: Handles successful creation of the target tags: - - project-config - /project-config/default/{gitUrl}: - get: - description: Get project configs by git url - operationId: GetDefaultProjectConfig + - target + /target/{targetId}/metadata: + post: + description: Update target metadata + operationId: UpdateTargetMetadata parameters: - - description: Git URL + - description: Target ID in: path - name: gitUrl + name: targetId required: true type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/ProjectConfig' - summary: Get project configs by git url - tags: - - project-config - /project-config/prebuild: - get: - consumes: - - application/json - description: List prebuilds - operationId: ListPrebuilds + - description: Target Metadata + in: body + name: targetMetadata + required: true + schema: + $ref: '#/definitions/UpdateTargetMetadataDTO' responses: "200": description: OK - schema: - items: - $ref: '#/definitions/PrebuildDTO' - type: array - summary: List prebuilds + summary: Update target metadata tags: - - prebuild - /project-config/prebuild/process-git-event: + - target + /target/{targetId}/provider-metadata: post: - description: ProcessGitEvent - operationId: ProcessGitEvent + description: Update target provider metadata + operationId: UpdateTargetProviderMetadata parameters: - - description: Webhook event + - description: Target ID + in: path + name: targetId + required: true + type: string + - description: Provider metadata in: body - name: workspace + name: metadata required: true schema: - type: object - responses: - "200": - description: OK - summary: ProcessGitEvent - tags: - - prebuild - /provider: - get: - description: List providers - operationId: ListProviders - produces: - - application/json + $ref: '#/definitions/UpdateTargetProviderMetadataDTO' responses: "200": description: OK - schema: - items: - $ref: '#/definitions/Provider' - type: array - summary: List providers + summary: Update target provider metadata tags: - - provider - /provider/{provider}/target-manifest: - get: - description: Get provider target manifest - operationId: GetTargetManifest + - target + /target/{targetId}/restart: + post: + description: Restart target + operationId: RestartTarget parameters: - - description: Provider name + - description: Target ID or Name in: path - name: provider + name: targetId required: true type: string responses: "200": description: OK - schema: - $ref: '#/definitions/ProviderTargetManifest' - summary: Get provider target manifest + summary: Restart target tags: - - provider - /provider/{provider}/uninstall: - post: - consumes: - - application/json - description: Uninstall a provider - operationId: UninstallProvider + - target + /target/{targetId}/set-default: + patch: + description: Set target to be used by default + operationId: SetDefaultTarget parameters: - - description: Provider to uninstall + - description: Target ID or name in: path - name: provider + name: targetId required: true type: string responses: "200": description: OK - summary: Uninstall a provider + summary: Set target to be used by default tags: - - provider - /provider/install: + - target + /target/{targetId}/start: post: - consumes: - - application/json - description: Install a provider - operationId: InstallProvider + description: Start target + operationId: StartTarget parameters: - - description: Provider to install - in: body - name: provider + - description: Target ID or Name + in: path + name: targetId required: true - schema: - $ref: '#/definitions/InstallProviderRequest' + type: string responses: "200": description: OK - summary: Install a provider + summary: Start target tags: - - provider - /sample: + - target + /target/{targetId}/state: get: - description: List samples - operationId: ListSamples + description: Get target state + operationId: GetTargetState + parameters: + - description: Target ID or Name + in: path + name: targetId + required: true + type: string produces: - application/json responses: "200": description: OK schema: - items: - $ref: '#/definitions/Sample' - type: array - summary: List samples + $ref: '#/definitions/ResourceState' + summary: Get target state tags: - - sample - /server/config: + - target + /target/{targetId}/stop: + post: + description: Stop target + operationId: StopTarget + parameters: + - description: Target ID or Name + in: path + name: targetId + required: true + type: string + responses: + "200": + description: OK + summary: Stop target + tags: + - target + /workspace: get: - description: Get the server configuration - operationId: GetConfig + description: List workspaces + operationId: ListWorkspaces + parameters: + - description: JSON encoded labels + in: query + name: labels + type: string produces: - application/json responses: "200": description: OK schema: - $ref: '#/definitions/ServerConfig' - summary: Get the server configuration + items: + $ref: '#/definitions/WorkspaceDTO' + type: array + summary: List workspaces tags: - - server + - workspace post: - consumes: - - application/json - description: Set the server configuration - operationId: SetConfig + description: Create a workspace + operationId: CreateWorkspace parameters: - - description: Server configuration + - description: Create workspace in: body - name: config + name: workspace required: true schema: - $ref: '#/definitions/ServerConfig' + $ref: '#/definitions/CreateWorkspaceDTO' produces: - application/json responses: "200": description: OK schema: - $ref: '#/definitions/ServerConfig' - summary: Set the server configuration + $ref: '#/definitions/WorkspaceDTO' + summary: Create a workspace tags: - - server - /server/logs: + - workspace + /workspace-template: get: - description: List server log files - operationId: GetServerLogFiles + description: List workspace templates + operationId: ListWorkspaceTemplates produces: - application/json responses: @@ -2274,134 +2947,239 @@ paths: description: OK schema: items: - type: string + $ref: '#/definitions/WorkspaceTemplate' type: array - summary: List server log files + summary: List workspace templates tags: - - server - /server/network-key: - post: - description: Generate a new authentication key - operationId: GenerateNetworkKey - produces: + - workspace-template + put: + consumes: + - application/json + description: Set workspace template data + operationId: SaveWorkspaceTemplate + parameters: + - description: Workspace template + in: body + name: workspaceTemplate + required: true + schema: + $ref: '#/definitions/CreateWorkspaceTemplateDTO' + responses: + "201": + description: Created + summary: Set workspace template data + tags: + - workspace-template + /workspace-template/{templateName}: + delete: + description: Delete workspace template data + operationId: DeleteWorkspaceTemplate + parameters: + - description: Template name + in: path + name: templateName + required: true + type: string + - description: Force + in: query + name: force + type: boolean + responses: + "204": + description: No Content + summary: Delete workspace template data + tags: + - workspace-template + get: + consumes: - application/json + description: Find a workspace template + operationId: FindWorkspaceTemplate + parameters: + - description: Template name + in: path + name: templateName + required: true + type: string responses: "200": description: OK schema: - $ref: '#/definitions/NetworkKey' - summary: Generate a new authentication key + $ref: '#/definitions/WorkspaceTemplate' + summary: Find a workspace template tags: - - server - /target: + - workspace-template + /workspace-template/{templateName}/prebuild: get: - description: List targets - operationId: ListTargets - produces: + consumes: - application/json + description: List prebuilds for workspace template + operationId: ListPrebuildsForWorkspaceTemplate + parameters: + - description: Template name + in: path + name: templateName + required: true + type: string responses: "200": description: OK schema: items: - $ref: '#/definitions/ProviderTarget' + $ref: '#/definitions/PrebuildDTO' type: array - summary: List targets + summary: List prebuilds for workspace template tags: - - target + - prebuild put: - description: Set a target - operationId: SetTarget + consumes: + - application/json + description: Save prebuild + operationId: SavePrebuild parameters: - - description: Target to set + - description: Template name + in: path + name: templateName + required: true + type: string + - description: Prebuild in: body - name: target + name: prebuild required: true schema: - $ref: '#/definitions/CreateProviderTargetDTO' + $ref: '#/definitions/CreatePrebuildDTO' responses: "201": description: Created - summary: Set a target + schema: + type: string + summary: Save prebuild tags: - - target - /target/{target}: + - prebuild + /workspace-template/{templateName}/prebuild/{prebuildId}: delete: - description: Remove a target - operationId: RemoveTarget + consumes: + - application/json + description: Delete prebuild + operationId: DeletePrebuild + parameters: + - description: Workspace template name + in: path + name: templateName + required: true + type: string + - description: Prebuild ID + in: path + name: prebuildId + required: true + type: string + - description: Force + in: query + name: force + type: boolean + responses: + "204": + description: No Content + summary: Delete prebuild + tags: + - prebuild + get: + consumes: + - application/json + description: Find prebuild + operationId: FindPrebuild parameters: - - description: Target name + - description: Workspace template name + in: path + name: templateName + required: true + type: string + - description: Prebuild ID in: path - name: target + name: prebuildId required: true type: string responses: - "204": - description: No Content - summary: Remove a target + "200": + description: OK + schema: + $ref: '#/definitions/PrebuildDTO' + summary: Find prebuild tags: - - target - /target/{target}/set-default: + - prebuild + /workspace-template/{templateName}/set-default: patch: - description: Set target to default - operationId: SetDefaultTarget + description: Set workspace template to default + operationId: SetDefaultWorkspaceTemplate parameters: - - description: Target name + - description: Template name in: path - name: target + name: templateName required: true type: string responses: "200": description: OK - summary: Set target to default + summary: Set workspace template to default tags: - - target - /workspace: + - workspace-template + /workspace-template/default/{gitUrl}: get: - description: List workspaces - operationId: ListWorkspaces + description: Get default workspace templates by git url + operationId: GetDefaultWorkspaceTemplate parameters: - - description: Verbose - in: query - name: verbose - type: boolean + - description: Git URL + in: path + name: gitUrl + required: true + type: string produces: - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/WorkspaceTemplate' + summary: Get default workspace templates by git url + tags: + - workspace-template + /workspace-template/prebuild: + get: + consumes: + - application/json + description: List prebuilds + operationId: ListPrebuilds responses: "200": description: OK schema: items: - $ref: '#/definitions/WorkspaceDTO' + $ref: '#/definitions/PrebuildDTO' type: array - summary: List workspaces + summary: List prebuilds tags: - - workspace + - prebuild + /workspace-template/prebuild/process-git-event: post: - description: Create a workspace - operationId: CreateWorkspace + description: ProcessGitEvent + operationId: ProcessGitEvent parameters: - - description: Create workspace + - description: Webhook event in: body - name: workspace + name: body required: true schema: - $ref: '#/definitions/CreateWorkspaceDTO' - produces: - - application/json + type: object responses: "200": description: OK - schema: - $ref: '#/definitions/Workspace' - summary: Create a workspace + summary: ProcessGitEvent tags: - - workspace + - prebuild /workspace/{workspaceId}: delete: - description: Remove workspace - operationId: RemoveWorkspace + description: Delete workspace + operationId: DeleteWorkspace parameters: - description: Workspace ID in: path @@ -2415,22 +3193,18 @@ paths: responses: "200": description: OK - summary: Remove workspace + summary: Delete workspace tags: - workspace get: - description: Get workspace info - operationId: GetWorkspace + description: Find workspace + operationId: FindWorkspace parameters: - description: Workspace ID or Name in: path name: workspaceId required: true type: string - - description: Verbose - in: query - name: verbose - type: boolean produces: - application/json responses: @@ -2438,91 +3212,155 @@ paths: description: OK schema: $ref: '#/definitions/WorkspaceDTO' - summary: Get workspace info + summary: Find workspace tags: - workspace - /workspace/{workspaceId}/{projectId}/start: + /workspace/{workspaceId}/labels: post: - description: Start project - operationId: StartProject + description: Update workspace labels + operationId: UpdateWorkspaceLabels parameters: - description: Workspace ID or Name in: path name: workspaceId required: true type: string - - description: Project ID - in: path - name: projectId + - description: Labels + in: body + name: labels required: true - type: string + schema: + additionalProperties: + type: string + type: object responses: "200": description: OK - summary: Start project + schema: + $ref: '#/definitions/WorkspaceDTO' + summary: Update workspace labels tags: - workspace - /workspace/{workspaceId}/{projectId}/state: + /workspace/{workspaceId}/metadata: post: - description: Set project state - operationId: SetProjectState + description: Update workspace metadata + operationId: UpdateWorkspaceMetadata parameters: - - description: Workspace ID or Name + - description: Workspace ID in: path name: workspaceId required: true type: string - - description: Project ID + - description: Workspace Metadata + in: body + name: workspaceMetadata + required: true + schema: + $ref: '#/definitions/UpdateWorkspaceMetadataDTO' + responses: + "200": + description: OK + summary: Update workspace metadata + tags: + - workspace + /workspace/{workspaceId}/provider-metadata: + post: + description: Update workspace provider metadata + operationId: UpdateWorkspaceProviderMetadata + parameters: + - description: Workspace ID in: path - name: projectId + name: workspaceId required: true type: string - - description: Set State + - description: Provider metadata in: body - name: setState + name: metadata required: true schema: - $ref: '#/definitions/SetProjectState' + $ref: '#/definitions/UpdateWorkspaceProviderMetadataDTO' responses: "200": description: OK - summary: Set project state + summary: Update workspace provider metadata tags: - workspace - /workspace/{workspaceId}/{projectId}/stop: + /workspace/{workspaceId}/restart: post: - description: Stop project - operationId: StopProject + description: Restart workspace + operationId: RestartWorkspace parameters: - description: Workspace ID or Name in: path name: workspaceId required: true type: string - - description: Project ID + responses: + "200": + description: OK + summary: Restart workspace + tags: + - workspace + /workspace/{workspaceId}/start: + post: + description: Start workspace + operationId: StartWorkspace + parameters: + - description: Workspace ID or Name in: path - name: projectId + name: workspaceId required: true type: string responses: "200": description: OK - summary: Stop project + summary: Start workspace tags: - workspace - /workspace/{workspaceId}/{projectId}/toolbox/files: - delete: - description: Delete file inside workspace project - operationId: FsDeleteFile + /workspace/{workspaceId}/state: + get: + description: Get workspace state + operationId: GetWorkspaceState parameters: - description: Workspace ID or Name in: path name: workspaceId required: true type: string - - description: Project ID + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/ResourceState' + summary: Get workspace state + tags: + - workspace + /workspace/{workspaceId}/stop: + post: + description: Stop workspace + operationId: StopWorkspace + parameters: + - description: Workspace ID or Name + in: path + name: workspaceId + required: true + type: string + responses: + "200": + description: OK + summary: Stop workspace + tags: + - workspace + /workspace/{workspaceId}/toolbox/files: + delete: + description: Delete file inside a workspace + operationId: FsDeleteFile + parameters: + - description: Workspace ID or Name in: path - name: projectId + name: workspaceId required: true type: string - description: Path @@ -2539,7 +3377,7 @@ paths: tags: - workspace toolbox get: - description: List files inside workspace project + description: List files inside a workspace operationId: FsListFiles parameters: - description: Workspace ID or Name @@ -2547,11 +3385,6 @@ paths: name: workspaceId required: true type: string - - description: Project ID - in: path - name: projectId - required: true - type: string - description: Path in: query name: path @@ -2568,9 +3401,9 @@ paths: summary: List files tags: - workspace toolbox - /workspace/{workspaceId}/{projectId}/toolbox/files/download: + /workspace/{workspaceId}/toolbox/files/download: get: - description: Download file from workspace project + description: Download file from a workspace operationId: FsDownloadFile parameters: - description: Workspace ID or Name @@ -2578,11 +3411,6 @@ paths: name: workspaceId required: true type: string - - description: Project ID - in: path - name: projectId - required: true - type: string - description: Path in: query name: path @@ -2598,9 +3426,9 @@ paths: summary: Download file tags: - workspace toolbox - /workspace/{workspaceId}/{projectId}/toolbox/files/find: + /workspace/{workspaceId}/toolbox/files/find: get: - description: Search for text/pattern inside workspace project files + description: Search for text/pattern inside a workspace files operationId: FsFindInFiles parameters: - description: Workspace ID or Name @@ -2608,11 +3436,6 @@ paths: name: workspaceId required: true type: string - - description: Project ID - in: path - name: projectId - required: true - type: string - description: Path in: query name: path @@ -2635,9 +3458,9 @@ paths: summary: Search for text/pattern in files tags: - workspace toolbox - /workspace/{workspaceId}/{projectId}/toolbox/files/folder: + /workspace/{workspaceId}/toolbox/files/folder: post: - description: Create folder inside workspace project + description: Create folder inside a workspace operationId: FsCreateFolder parameters: - description: Workspace ID or Name @@ -2645,11 +3468,6 @@ paths: name: workspaceId required: true type: string - - description: Project ID - in: path - name: projectId - required: true - type: string - description: Path in: query name: path @@ -2668,9 +3486,9 @@ paths: summary: Create folder tags: - workspace toolbox - /workspace/{workspaceId}/{projectId}/toolbox/files/info: + /workspace/{workspaceId}/toolbox/files/info: get: - description: Get file info inside workspace project + description: Get file info inside a workspace operationId: FsGetFileDetails parameters: - description: Workspace ID or Name @@ -2678,11 +3496,6 @@ paths: name: workspaceId required: true type: string - - description: Project ID - in: path - name: projectId - required: true - type: string - description: Path in: query name: path @@ -2698,9 +3511,9 @@ paths: summary: Get file info tags: - workspace toolbox - /workspace/{workspaceId}/{projectId}/toolbox/files/move: + /workspace/{workspaceId}/toolbox/files/move: post: - description: Create folder inside workspace project + description: Create folder inside a workspace operationId: FsMoveFile parameters: - description: Workspace ID or Name @@ -2708,11 +3521,6 @@ paths: name: workspaceId required: true type: string - - description: Project ID - in: path - name: projectId - required: true - type: string - description: Source path in: query name: source @@ -2731,9 +3539,9 @@ paths: summary: Create folder tags: - workspace toolbox - /workspace/{workspaceId}/{projectId}/toolbox/files/permissions: + /workspace/{workspaceId}/toolbox/files/permissions: post: - description: Set file owner/group/permissions inside workspace project + description: Set file owner/group/permissions inside a workspace operationId: FsSetFilePermissions parameters: - description: Workspace ID or Name @@ -2741,11 +3549,6 @@ paths: name: workspaceId required: true type: string - - description: Project ID - in: path - name: projectId - required: true - type: string - description: Path in: query name: path @@ -2771,9 +3574,9 @@ paths: summary: Set file owner/group/permissions tags: - workspace toolbox - /workspace/{workspaceId}/{projectId}/toolbox/files/replace: + /workspace/{workspaceId}/toolbox/files/replace: post: - description: Repleace text/pattern in mutilple files inside workspace project + description: Repleace text/pattern in mutilple files inside a workspace operationId: FsReplaceInFiles parameters: - description: Workspace ID or Name @@ -2781,11 +3584,6 @@ paths: name: workspaceId required: true type: string - - description: Project ID - in: path - name: projectId - required: true - type: string - description: ReplaceParams in: body name: replace @@ -2804,9 +3602,9 @@ paths: summary: Repleace text/pattern in files tags: - workspace toolbox - /workspace/{workspaceId}/{projectId}/toolbox/files/search: + /workspace/{workspaceId}/toolbox/files/search: get: - description: Search for files inside workspace project + description: Search for files inside a workspace operationId: FsSearchFiles parameters: - description: Workspace ID or Name @@ -2814,11 +3612,6 @@ paths: name: workspaceId required: true type: string - - description: Project ID - in: path - name: projectId - required: true - type: string - description: Path in: query name: path @@ -2839,9 +3632,9 @@ paths: summary: Search for files tags: - workspace toolbox - /workspace/{workspaceId}/{projectId}/toolbox/files/upload: + /workspace/{workspaceId}/toolbox/files/upload: post: - description: Upload file inside workspace project + description: Upload file inside a workspace operationId: FsUploadFile parameters: - description: Workspace ID or Name @@ -2849,11 +3642,6 @@ paths: name: workspaceId required: true type: string - - description: Project ID - in: path - name: projectId - required: true - type: string - description: Path in: query name: path @@ -2872,7 +3660,7 @@ paths: summary: Upload file tags: - workspace toolbox - /workspace/{workspaceId}/{projectId}/toolbox/git/add: + /workspace/{workspaceId}/toolbox/git/add: post: description: Add files to git commit operationId: GitAddFiles @@ -2882,11 +3670,6 @@ paths: name: workspaceId required: true type: string - - description: Project ID - in: path - name: projectId - required: true - type: string - description: GitAddRequest in: body name: params @@ -2901,9 +3684,9 @@ paths: summary: Add files tags: - workspace toolbox - /workspace/{workspaceId}/{projectId}/toolbox/git/branches: + /workspace/{workspaceId}/toolbox/git/branches: get: - description: Get branch list from git repository inside workspace project + description: Get branch list from git repository inside a workspace operationId: GitBranchList parameters: - description: Workspace ID or Name @@ -2911,11 +3694,6 @@ paths: name: workspaceId required: true type: string - - description: Project ID - in: path - name: projectId - required: true - type: string - description: Path to git repository in: query name: path @@ -2932,7 +3710,7 @@ paths: tags: - workspace toolbox post: - description: Create branch on git repository inside workspace project + description: Create branch on git repository inside a workspace operationId: GitCreateBranch parameters: - description: Workspace ID or Name @@ -2940,11 +3718,6 @@ paths: name: workspaceId required: true type: string - - description: Project ID - in: path - name: projectId - required: true - type: string - description: GitBranchRequest in: body name: params @@ -2959,9 +3732,9 @@ paths: summary: Create branch tags: - workspace toolbox - /workspace/{workspaceId}/{projectId}/toolbox/git/clone: + /workspace/{workspaceId}/toolbox/git/clone: post: - description: Clone git repository inside workspace project + description: Clone git repository inside a workspace operationId: GitCloneRepository parameters: - description: Workspace ID or Name @@ -2969,11 +3742,6 @@ paths: name: workspaceId required: true type: string - - description: Project ID - in: path - name: projectId - required: true - type: string - description: GitCloneRequest in: body name: params @@ -2988,9 +3756,9 @@ paths: summary: Clone git repository tags: - workspace toolbox - /workspace/{workspaceId}/{projectId}/toolbox/git/commit: + /workspace/{workspaceId}/toolbox/git/commit: post: - description: Commit changes to git repository inside workspace project + description: Commit changes to git repository inside a workspace operationId: GitCommitChanges parameters: - description: Workspace ID or Name @@ -2998,11 +3766,6 @@ paths: name: workspaceId required: true type: string - - description: Project ID - in: path - name: projectId - required: true - type: string - description: GitCommitRequest in: body name: params @@ -3019,9 +3782,9 @@ paths: summary: Commit changes tags: - workspace toolbox - /workspace/{workspaceId}/{projectId}/toolbox/git/history: + /workspace/{workspaceId}/toolbox/git/history: get: - description: Get commit history from git repository inside workspace project + description: Get commit history from git repository inside a workspace operationId: GitCommitHistory parameters: - description: Workspace ID or Name @@ -3029,11 +3792,6 @@ paths: name: workspaceId required: true type: string - - description: Project ID - in: path - name: projectId - required: true - type: string - description: Path to git repository in: query name: path @@ -3051,9 +3809,9 @@ paths: summary: Get commit history tags: - workspace toolbox - /workspace/{workspaceId}/{projectId}/toolbox/git/pull: + /workspace/{workspaceId}/toolbox/git/pull: post: - description: Pull changes from remote to git repository inside workspace project + description: Pull changes from remote to git repository inside a workspace operationId: GitPullChanges parameters: - description: Workspace ID or Name @@ -3061,11 +3819,6 @@ paths: name: workspaceId required: true type: string - - description: Project ID - in: path - name: projectId - required: true - type: string - description: Git pull request in: body name: params @@ -3080,9 +3833,9 @@ paths: summary: Pull changes tags: - workspace toolbox - /workspace/{workspaceId}/{projectId}/toolbox/git/push: + /workspace/{workspaceId}/toolbox/git/push: post: - description: Push changes to remote from git repository inside workspace project + description: Push changes to remote from git repository inside a workspace operationId: GitPushChanges parameters: - description: Workspace ID or Name @@ -3090,11 +3843,6 @@ paths: name: workspaceId required: true type: string - - description: Project ID - in: path - name: projectId - required: true - type: string - description: Git push request in: body name: params @@ -3109,9 +3857,9 @@ paths: summary: Push changes tags: - workspace toolbox - /workspace/{workspaceId}/{projectId}/toolbox/git/status: + /workspace/{workspaceId}/toolbox/git/status: get: - description: Get status from git repository inside workspace project + description: Get status from git repository inside a workspace operationId: GitGitStatus parameters: - description: Workspace ID or Name @@ -3119,11 +3867,6 @@ paths: name: workspaceId required: true type: string - - description: Project ID - in: path - name: projectId - required: true - type: string - description: Path to git repository in: query name: path @@ -3139,7 +3882,7 @@ paths: summary: Get git status tags: - workspace toolbox - /workspace/{workspaceId}/{projectId}/toolbox/lsp/completions: + /workspace/{workspaceId}/toolbox/lsp/completions: post: description: The Completion request is sent from the client to the server to compute completion items at a given cursor position. @@ -3150,11 +3893,6 @@ paths: name: workspaceId required: true type: string - - description: Project ID - in: path - name: projectId - required: true - type: string - description: LspCompletionParams in: body name: params @@ -3171,7 +3909,7 @@ paths: summary: Get Lsp Completions tags: - workspace toolbox - /workspace/{workspaceId}/{projectId}/toolbox/lsp/did-close: + /workspace/{workspaceId}/toolbox/lsp/did-close: post: description: The document close notification is sent from the client to the server when the document got closed in the client. @@ -3182,11 +3920,6 @@ paths: name: workspaceId required: true type: string - - description: Project ID - in: path - name: projectId - required: true - type: string - description: LspDocumentRequest in: body name: params @@ -3201,7 +3934,7 @@ paths: summary: Call Lsp DidClose tags: - workspace toolbox - /workspace/{workspaceId}/{projectId}/toolbox/lsp/did-open: + /workspace/{workspaceId}/toolbox/lsp/did-open: post: description: The document open notification is sent from the client to the server to signal newly opened text documents. @@ -3212,11 +3945,6 @@ paths: name: workspaceId required: true type: string - - description: Project ID - in: path - name: projectId - required: true - type: string - description: LspDocumentRequest in: body name: params @@ -3231,7 +3959,7 @@ paths: summary: Call Lsp DidOpen tags: - workspace toolbox - /workspace/{workspaceId}/{projectId}/toolbox/lsp/document-symbols: + /workspace/{workspaceId}/toolbox/lsp/document-symbols: get: description: The document symbol request is sent from the client to the server. operationId: LspDocumentSymbols @@ -3241,11 +3969,6 @@ paths: name: workspaceId required: true type: string - - description: Project ID - in: path - name: projectId - required: true - type: string - description: Language ID in: query name: languageId @@ -3273,9 +3996,9 @@ paths: summary: Call Lsp DocumentSymbols tags: - workspace toolbox - /workspace/{workspaceId}/{projectId}/toolbox/lsp/start: + /workspace/{workspaceId}/toolbox/lsp/start: post: - description: Start Lsp server process inside workspace project + description: Start Lsp server process inside a workspace operationId: LspStart parameters: - description: Workspace ID or Name @@ -3283,11 +4006,6 @@ paths: name: workspaceId required: true type: string - - description: Project ID - in: path - name: projectId - required: true - type: string - description: LspServerRequest in: body name: params @@ -3302,9 +4020,9 @@ paths: summary: Start Lsp server tags: - workspace toolbox - /workspace/{workspaceId}/{projectId}/toolbox/lsp/stop: + /workspace/{workspaceId}/toolbox/lsp/stop: post: - description: Stop Lsp server process inside workspace project + description: Stop Lsp server process inside a workspace operationId: LspStop parameters: - description: Workspace ID or Name @@ -3312,11 +4030,6 @@ paths: name: workspaceId required: true type: string - - description: Project ID - in: path - name: projectId - required: true - type: string - description: LspServerRequest in: body name: params @@ -3331,7 +4044,7 @@ paths: summary: Stop Lsp server tags: - workspace toolbox - /workspace/{workspaceId}/{projectId}/toolbox/lsp/workspace-symbols: + /workspace/{workspaceId}/toolbox/lsp/workspace-symbols: get: description: The workspace symbol request is sent from the client to the server to list project-wide symbols matching the query string. @@ -3342,11 +4055,6 @@ paths: name: workspaceId required: true type: string - - description: Project ID - in: path - name: projectId - required: true - type: string - description: Language ID in: query name: languageId @@ -3374,9 +4082,9 @@ paths: summary: Call Lsp WorkspaceSymbols tags: - workspace toolbox - /workspace/{workspaceId}/{projectId}/toolbox/process/execute: + /workspace/{workspaceId}/toolbox/process/execute: post: - description: Execute command synchronously inside workspace project + description: Execute command synchronously inside a workspace operationId: ProcessExecuteCommand parameters: - description: Workspace ID or Name @@ -3384,11 +4092,6 @@ paths: name: workspaceId required: true type: string - - description: Project ID - in: path - name: projectId - required: true - type: string - description: Execute command request in: body name: params @@ -3405,7 +4108,7 @@ paths: summary: Execute command tags: - workspace toolbox - /workspace/{workspaceId}/{projectId}/toolbox/process/session: + /workspace/{workspaceId}/toolbox/process/session: get: description: List sessions inside workspace project operationId: ListSessions @@ -3415,11 +4118,6 @@ paths: name: workspaceId required: true type: string - - description: Project ID - in: path - name: projectId - required: true - type: string produces: - application/json responses: @@ -3441,11 +4139,6 @@ paths: name: workspaceId required: true type: string - - description: Project ID - in: path - name: projectId - required: true - type: string - description: Create session request in: body name: params @@ -3460,7 +4153,7 @@ paths: summary: Create exec session tags: - workspace toolbox - /workspace/{workspaceId}/{projectId}/toolbox/process/session/{sessionId}: + /workspace/{workspaceId}/toolbox/process/session/{sessionId}: delete: description: Delete a session inside workspace project operationId: DeleteSession @@ -3470,11 +4163,6 @@ paths: name: workspaceId required: true type: string - - description: Project ID - in: path - name: projectId - required: true - type: string - description: Session ID in: path name: sessionId @@ -3488,7 +4176,7 @@ paths: summary: Delete session tags: - workspace toolbox - /workspace/{workspaceId}/{projectId}/toolbox/process/session/{sessionId}/command/{commandId}/logs: + /workspace/{workspaceId}/toolbox/process/session/{sessionId}/command/{commandId}/logs: get: description: |- Get logs of a command inside a session inside workspace project @@ -3500,11 +4188,6 @@ paths: name: workspaceId required: true type: string - - description: Project ID - in: path - name: projectId - required: true - type: string - description: Session ID in: path name: sessionId @@ -3523,7 +4206,7 @@ paths: summary: Get session command logs tags: - workspace toolbox - /workspace/{workspaceId}/{projectId}/toolbox/process/session/{sessionId}/exec: + /workspace/{workspaceId}/toolbox/process/session/{sessionId}/exec: post: description: Execute command inside a session inside workspace project operationId: SessionExecuteCommand @@ -3533,11 +4216,6 @@ paths: name: workspaceId required: true type: string - - description: Project ID - in: path - name: projectId - required: true - type: string - description: Session ID in: path name: sessionId @@ -3559,63 +4237,26 @@ paths: summary: Execute command in session tags: - workspace toolbox - /workspace/{workspaceId}/{projectId}/toolbox/project-dir: + /workspace/{workspaceId}/toolbox/workspace-dir: get: - description: Get project directory - operationId: GetProjectDir + description: Get workspace directory + operationId: GetWorkspaceDir parameters: - description: Workspace ID or Name in: path name: workspaceId required: true type: string - - description: Project ID - in: path - name: projectId - required: true - type: string produces: - application/json responses: "200": description: OK schema: - $ref: '#/definitions/ProjectDirResponse' - summary: Get project dir + $ref: '#/definitions/WorkspaceDirResponse' + summary: Get workspace dir tags: - workspace toolbox - /workspace/{workspaceId}/start: - post: - description: Start workspace - operationId: StartWorkspace - parameters: - - description: Workspace ID or Name - in: path - name: workspaceId - required: true - type: string - responses: - "200": - description: OK - summary: Start workspace - tags: - - workspace - /workspace/{workspaceId}/stop: - post: - description: Stop workspace - operationId: StopWorkspace - parameters: - - description: Workspace ID or Name - in: path - name: workspaceId - required: true - type: string - responses: - "200": - description: OK - summary: Stop workspace - tags: - - workspace schemes: - http security: diff --git a/pkg/api/middlewares/auth.go b/pkg/api/middlewares/auth.go index 441b7144ec..5135d80024 100644 --- a/pkg/api/middlewares/auth.go +++ b/pkg/api/middlewares/auth.go @@ -5,22 +5,15 @@ package middlewares import ( "errors" - "strings" - "github.com/daytonaio/daytona/pkg/apikey" + "github.com/daytonaio/daytona/pkg/api/util" "github.com/daytonaio/daytona/pkg/server" "github.com/gin-gonic/gin" ) func AuthMiddleware() gin.HandlerFunc { return func(ctx *gin.Context) { - bearerToken := ctx.GetHeader("Authorization") - if bearerToken == "" { - ctx.AbortWithError(401, errors.New("unauthorized")) - return - } - - token := ExtractToken(bearerToken) + token := util.ExtractToken(ctx) if token == "" { ctx.AbortWithError(401, errors.New("unauthorized")) return @@ -28,28 +21,18 @@ func AuthMiddleware() gin.HandlerFunc { server := server.GetInstance(nil) - if !server.ApiKeyService.IsValidApiKey(token) { + if !server.ApiKeyService.IsValidApiKey(ctx.Request.Context(), token) { ctx.AbortWithError(401, errors.New("unauthorized")) return } - apiKeyType := apikey.ApiKeyTypeClient - - if server.ApiKeyService.IsWorkspaceApiKey(token) { - apiKeyType = apikey.ApiKeyTypeWorkspace - } else if server.ApiKeyService.IsProjectApiKey(token) { - apiKeyType = apikey.ApiKeyTypeProject + apiKeyType, err := server.ApiKeyService.GetApiKeyType(ctx.Request.Context(), token) + if err != nil { + ctx.AbortWithError(401, errors.New("unauthorized")) + return } ctx.Set("apiKeyType", apiKeyType) ctx.Next() } } - -func ExtractToken(bearerToken string) string { - if !strings.HasPrefix(bearerToken, "Bearer ") { - return "" - } - - return strings.TrimPrefix(bearerToken, "Bearer ") -} diff --git a/pkg/api/middlewares/logging.go b/pkg/api/middlewares/logging.go index 044b3bc7fd..8bda73e8ca 100644 --- a/pkg/api/middlewares/logging.go +++ b/pkg/api/middlewares/logging.go @@ -11,6 +11,18 @@ import ( log "github.com/sirupsen/logrus" ) +var ignoreLoggingPaths = map[string]bool{ + "/job/": true, + "/workspace/:workspaceId/metadata": true, + "/workspace/:workspaceId/state": true, + "/target/:targetId/metadata": true, + "/target/:targetId/state": true, + "/runner/:runnerId/jobs": true, + "/runner/:runnerId/metadata": true, + "/runner/:runnerId/provider": true, + "/runner/:runnerId/jobs/:jobId/state": true, +} + func LoggingMiddleware() gin.HandlerFunc { return func(ctx *gin.Context) { startTime := time.Now() @@ -31,12 +43,22 @@ func LoggingMiddleware() gin.HandlerFunc { }).Error("API ERROR") ctx.JSON(statusCode, gin.H{"error": ctx.Errors[0].Err.Error()}) } else { - log.WithFields(log.Fields{ - "method": reqMethod, - "URI": reqUri, - "status": statusCode, - "latency": latencyTime, - }).Info("API REQUEST") + fullPath := ctx.FullPath() + if ignoreLoggingPaths[fullPath] { + log.WithFields(log.Fields{ + "method": reqMethod, + "URI": reqUri, + "status": statusCode, + "latency": latencyTime, + }).Debug("API REQUEST") + } else { + log.WithFields(log.Fields{ + "method": reqMethod, + "URI": reqUri, + "status": statusCode, + "latency": latencyTime, + }).Info("API REQUEST") + } } ctx.Next() diff --git a/pkg/api/middlewares/project.go b/pkg/api/middlewares/runner.go similarity index 60% rename from pkg/api/middlewares/project.go rename to pkg/api/middlewares/runner.go index 5e03371218..a3e4f098f0 100644 --- a/pkg/api/middlewares/project.go +++ b/pkg/api/middlewares/runner.go @@ -6,28 +6,31 @@ package middlewares import ( "errors" + "github.com/daytonaio/daytona/pkg/api/util" + "github.com/daytonaio/daytona/pkg/models" "github.com/daytonaio/daytona/pkg/server" "github.com/gin-gonic/gin" ) -func ProjectAuthMiddleware() gin.HandlerFunc { +func RunnerAuthMiddleware() gin.HandlerFunc { return func(ctx *gin.Context) { - bearerToken := ctx.GetHeader("Authorization") - if bearerToken == "" { + token := util.ExtractToken(ctx) + if token == "" { ctx.AbortWithError(401, errors.New("unauthorized")) return } - token := ExtractToken(bearerToken) - if token == "" { + server := server.GetInstance(nil) + + apiKeyType, err := server.ApiKeyService.GetApiKeyType(ctx.Request.Context(), token) + if err != nil { ctx.AbortWithError(401, errors.New("unauthorized")) return } - server := server.GetInstance(nil) - - if !server.ApiKeyService.IsProjectApiKey(token) && !server.ApiKeyService.IsWorkspaceApiKey(token) { + if apiKeyType != models.ApiKeyTypeRunner { ctx.AbortWithError(401, errors.New("unauthorized")) + return } ctx.Next() diff --git a/pkg/api/middlewares/telemetry.go b/pkg/api/middlewares/telemetry.go index b987ced390..19aa21d052 100644 --- a/pkg/api/middlewares/telemetry.go +++ b/pkg/api/middlewares/telemetry.go @@ -5,23 +5,14 @@ package middlewares import ( "context" - "strings" - "time" "github.com/daytonaio/daytona/internal" "github.com/daytonaio/daytona/pkg/server" "github.com/daytonaio/daytona/pkg/telemetry" "github.com/gin-gonic/gin" "github.com/google/uuid" - log "github.com/sirupsen/logrus" ) -var ignorePaths = map[string]bool{ - "/health": true, - "/workspace/:workspaceId/:projectId/state": true, - "/server/network-key": true, -} - func TelemetryMiddleware(telemetryService telemetry.TelemetryService) gin.HandlerFunc { return func(ctx *gin.Context) { if telemetryService == nil { @@ -29,17 +20,6 @@ func TelemetryMiddleware(telemetryService telemetry.TelemetryService) gin.Handle return } - if ctx.GetHeader(telemetry.ENABLED_HEADER) != "true" { - ctx.Next() - return - } - - reqUri := ctx.FullPath() - if ignorePaths[reqUri] { - ctx.Next() - return - } - clientId := ctx.GetHeader(telemetry.CLIENT_ID_HEADER) if clientId == "" { clientId = uuid.NewString() @@ -59,57 +39,6 @@ func TelemetryMiddleware(telemetryService telemetry.TelemetryService) gin.Handle ctx.Request = ctx.Request.WithContext(telemetryCtx) - source := ctx.GetHeader(telemetry.SOURCE_HEADER) - - reqMethod := ctx.Request.Method - - query := ctx.Request.URL.RawQuery - - remoteProfile := false - if source == string(telemetry.CLI_SOURCE) && !strings.Contains(ctx.Request.Host, "localhost") { - remoteProfile = true - } - - err := telemetryService.TrackServerEvent(telemetry.ServerEventApiRequestStarted, clientId, map[string]interface{}{ - "method": reqMethod, - "URI": reqUri, - "query": query, - "source": source, - "server_id": server.Id, - "session_id": sessionId, - "remote_profile": remoteProfile, - }) - if err != nil { - log.Trace(err) - } - - startTime := time.Now() - ctx.Next() - endTime := time.Now() - execTime := endTime.Sub(startTime) - statusCode := ctx.Writer.Status() - - properties := map[string]interface{}{ - "method": reqMethod, - "URI": reqUri, - "query": query, - "status": statusCode, - "source": source, - "exec time (µs)": execTime.Microseconds(), - "server_id": server.Id, - "session_id": sessionId, - "remote_profile": remoteProfile, - } - - if len(ctx.Errors) > 0 { - properties["error"] = ctx.Errors.String() - } - - err = telemetryService.TrackServerEvent(telemetry.ServerEventApiResponseSent, clientId, properties) - if err != nil { - log.Trace(err) - } - ctx.Next() } } diff --git a/pkg/api/middlewares/workspace.go b/pkg/api/middlewares/workspace.go new file mode 100644 index 0000000000..dd4b63c3bc --- /dev/null +++ b/pkg/api/middlewares/workspace.go @@ -0,0 +1,43 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package middlewares + +import ( + "errors" + + "github.com/daytonaio/daytona/pkg/api/util" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/server" + "github.com/gin-gonic/gin" +) + +func WorkspaceAuthMiddleware() gin.HandlerFunc { + return func(ctx *gin.Context) { + token := util.ExtractToken(ctx) + if token == "" { + ctx.AbortWithError(401, errors.New("unauthorized")) + return + } + + server := server.GetInstance(nil) + + apiKeyType, err := server.ApiKeyService.GetApiKeyType(ctx.Request.Context(), token) + if err != nil { + ctx.AbortWithError(401, errors.New("unauthorized")) + return + } + + switch apiKeyType { + case models.ApiKeyTypeWorkspace: + fallthrough + case models.ApiKeyTypeTarget: + ctx.Next() + default: + ctx.AbortWithError(401, errors.New("unauthorized")) + return + } + + ctx.Next() + } +} diff --git a/pkg/api/server.go b/pkg/api/server.go index bc2149fd90..54ce3e0bdf 100644 --- a/pkg/api/server.go +++ b/pkg/api/server.go @@ -36,18 +36,21 @@ import ( "github.com/daytonaio/daytona/pkg/api/controllers/binary" "github.com/daytonaio/daytona/pkg/api/controllers/build" "github.com/daytonaio/daytona/pkg/api/controllers/containerregistry" + "github.com/daytonaio/daytona/pkg/api/controllers/env" "github.com/daytonaio/daytona/pkg/api/controllers/gitprovider" "github.com/daytonaio/daytona/pkg/api/controllers/health" + "github.com/daytonaio/daytona/pkg/api/controllers/job" log_controller "github.com/daytonaio/daytona/pkg/api/controllers/log" - "github.com/daytonaio/daytona/pkg/api/controllers/profiledata" - "github.com/daytonaio/daytona/pkg/api/controllers/projectconfig" - "github.com/daytonaio/daytona/pkg/api/controllers/projectconfig/prebuild" - "github.com/daytonaio/daytona/pkg/api/controllers/provider" + "github.com/daytonaio/daytona/pkg/api/controllers/runner" + "github.com/daytonaio/daytona/pkg/api/controllers/runner/provider" "github.com/daytonaio/daytona/pkg/api/controllers/sample" "github.com/daytonaio/daytona/pkg/api/controllers/server" "github.com/daytonaio/daytona/pkg/api/controllers/target" + "github.com/daytonaio/daytona/pkg/api/controllers/targetconfig" "github.com/daytonaio/daytona/pkg/api/controllers/workspace" "github.com/daytonaio/daytona/pkg/api/controllers/workspace/toolbox" + "github.com/daytonaio/daytona/pkg/api/controllers/workspacetemplate" + "github.com/daytonaio/daytona/pkg/api/controllers/workspacetemplate/prebuild" "github.com/gin-gonic/gin" "github.com/gin-gonic/gin/binding" @@ -100,15 +103,14 @@ func (a *ApiServer) Start() error { binding.Validator = new(DefaultValidator) + a.router = gin.New() + a.router.Use(gin.Recovery()) if mode, ok := os.LookupEnv("DAYTONA_SERVER_MODE"); ok && mode == "development" { - a.router = gin.Default() a.router.Use(cors.New(cors.Config{ AllowAllOrigins: true, })) } else { gin.SetMode(gin.ReleaseMode) - a.router = gin.New() - a.router.Use(gin.Recovery()) } a.router.Use(middlewares.TelemetryMiddleware(a.telemetryService)) @@ -129,8 +131,8 @@ func (a *ApiServer) Start() error { serverController := protected.Group("/server") { serverController.GET("/config", server.GetConfig) - serverController.POST("/config", server.SetConfig) - serverController.POST("/network-key", server.GenerateNetworkKey) + serverController.PUT("/config", server.SaveConfig) + serverController.POST("/network-key", server.CreateNetworkKey) serverController.GET("/logs", server.GetServerLogFiles) } @@ -140,20 +142,26 @@ func (a *ApiServer) Start() error { binaryController.GET("/:version/:binaryName", binary.GetBinary) } - workspaceController := protected.Group("/workspace") + targetController := protected.Group("/target") { - workspaceController.GET("/:workspaceId", workspace.GetWorkspace) - workspaceController.GET("", workspace.ListWorkspaces) - workspaceController.POST("", workspace.CreateWorkspace) - workspaceController.POST("/:workspaceId/start", workspace.StartWorkspace) - workspaceController.POST("/:workspaceId/stop", workspace.StopWorkspace) - workspaceController.DELETE("/:workspaceId", workspace.RemoveWorkspace) - workspaceController.POST("/:workspaceId/:projectId/start", workspace.StartProject) - workspaceController.POST("/:workspaceId/:projectId/stop", workspace.StopProject) + targetController.GET("/:targetId", target.FindTarget) + targetController.GET("/:targetId/state", target.GetTargetState) + targetController.GET("", target.ListTargets) + targetController.POST("", target.CreateTarget) + targetController.POST("/:targetId/start", target.StartTarget) + targetController.POST("/:targetId/stop", target.StopTarget) + targetController.POST("/:targetId/restart", target.RestartTarget) + targetController.PATCH("/:targetId/set-default", target.SetDefaultTarget) + targetController.POST("/:targetId/handle-successful-creation", target.HandleSuccessfulCreation) + targetController.POST("/:targetId/provider-metadata", target.UpdateTargetProviderMetadata) + targetController.DELETE("/:targetId", target.DeleteTarget) + } - toolboxController := workspaceController.Group("/:workspaceId/:projectId/toolbox") + workspaceController := protected.Group("/workspace") + { + toolboxController := workspaceController.Group("/:workspaceId/toolbox") { - toolboxController.GET("/project-dir", toolbox.GetProjectDir) + toolboxController.GET("/workspace-dir", toolbox.GetWorkspaceDir) processController := toolboxController.Group("/process") { @@ -212,83 +220,92 @@ func (a *ApiServer) Start() error { lspController.POST("/stop", toolbox.LspStop) } } + + workspaceController.GET("/:workspaceId", workspace.FindWorkspace) + workspaceController.GET("/:workspaceId/state", workspace.GetWorkspaceState) + workspaceController.GET("", workspace.ListWorkspaces) + workspaceController.POST("", workspace.CreateWorkspace) + workspaceController.DELETE("/:workspaceId", workspace.DeleteWorkspace) + + workspaceController.POST("/:workspaceId/start", workspace.StartWorkspace) + workspaceController.POST("/:workspaceId/stop", workspace.StopWorkspace) + workspaceController.POST("/:workspaceId/restart", workspace.RestartWorkspace) + workspaceController.POST("/:workspaceId/provider-metadata", workspace.UpdateWorkspaceProviderMetadata) + workspaceController.POST("/:workspaceId/labels", workspace.UpdateWorkspaceLabels) } - projectConfigController := protected.Group("/project-config") + workspaceTemplateController := protected.Group("/workspace-template") { - // Defining the prebuild routes first to avoid conflicts with the project config routes + // Defining the prebuild routes first to avoid conflicts with the workspace template routes prebuildRoutePath := "/prebuild" - projectConfigPrebuildsGroup := projectConfigController.Group(prebuildRoutePath) + workspaceTemplatePrebuildsGroup := workspaceTemplateController.Group(prebuildRoutePath) { - projectConfigPrebuildsGroup.GET("", prebuild.ListPrebuilds) + workspaceTemplatePrebuildsGroup.GET("", prebuild.ListPrebuilds) } - projectConfigNameGroup := projectConfigController.Group(":configName") + workspaceTemplateNameGroup := workspaceTemplateController.Group(":templateName") { - projectConfigNameGroup.PUT(prebuildRoutePath, prebuild.SetPrebuild) - projectConfigNameGroup.GET(prebuildRoutePath, prebuild.ListPrebuildsForProjectConfig) - projectConfigNameGroup.GET(prebuildRoutePath+"/:prebuildId", prebuild.GetPrebuild) - projectConfigNameGroup.DELETE(prebuildRoutePath+"/:prebuildId", prebuild.DeletePrebuild) - - projectConfigNameGroup.GET("", projectconfig.GetProjectConfig) - projectConfigNameGroup.PATCH("/set-default", projectconfig.SetDefaultProjectConfig) - projectConfigNameGroup.DELETE("", projectconfig.DeleteProjectConfig) + workspaceTemplateNameGroup.PUT(prebuildRoutePath, prebuild.SavePrebuild) + workspaceTemplateNameGroup.GET(prebuildRoutePath, prebuild.ListPrebuildsForWorkspaceTemplate) + workspaceTemplateNameGroup.GET(prebuildRoutePath+"/:prebuildId", prebuild.FindPrebuild) + workspaceTemplateNameGroup.DELETE(prebuildRoutePath+"/:prebuildId", prebuild.DeletePrebuild) + + workspaceTemplateNameGroup.GET("", workspacetemplate.FindWorkspaceTemplate) + workspaceTemplateNameGroup.PATCH("/set-default", workspacetemplate.SetDefaultWorkspaceTemplate) + workspaceTemplateNameGroup.DELETE("", workspacetemplate.DeleteWorkspaceTemplate) } - projectConfigController.GET("", projectconfig.ListProjectConfigs) - projectConfigController.PUT("", projectconfig.SetProjectConfig) - projectConfigController.GET("/default/:gitUrl", projectconfig.GetDefaultProjectConfig) + workspaceTemplateController.GET("", workspacetemplate.ListWorkspaceTemplates) + workspaceTemplateController.PUT("", workspacetemplate.SaveWorkspaceTemplate) + workspaceTemplateController.GET("/default/:gitUrl", workspacetemplate.GetDefaultWorkspaceTemplate) } public.POST(constants.WEBHOOK_EVENT_ROUTE, prebuild.ProcessGitEvent) - providerController := protected.Group("/provider") - { - providerController.POST("/install", provider.InstallProvider) - providerController.GET("", provider.ListProviders) - providerController.POST("/:provider/uninstall", provider.UninstallProvider) - providerController.GET("/:provider/target-manifest", provider.GetTargetManifest) - } - - containerRegistryController := protected.Group("/container-registry") - { - containerRegistryController.GET("", containerregistry.ListContainerRegistries) - containerRegistryController.GET("/:server", containerregistry.GetContainerRegistry) - containerRegistryController.PUT("/:server", containerregistry.SetContainerRegistry) - containerRegistryController.DELETE("/:server", containerregistry.RemoveContainerRegistry) - } - buildController := protected.Group("/build") { buildController.POST("", build.CreateBuild) - buildController.GET("/:buildId", build.GetBuild) + buildController.GET("/:buildId", build.FindBuild) buildController.GET("", build.ListBuilds) + buildController.GET("/successful/:repoUrl", build.ListSuccessfulBuilds) buildController.DELETE("", build.DeleteAllBuilds) buildController.DELETE("/:buildId", build.DeleteBuild) buildController.DELETE("/prebuild/:prebuildId", build.DeleteBuildsFromPrebuild) } - targetController := protected.Group("/target") + targetConfigController := protected.Group("/target-config") { - targetController.GET("", target.ListTargets) - targetController.PUT("", target.SetTarget) - targetController.PATCH("/:target/set-default", target.SetDefaultTarget) - targetController.DELETE("/:target", target.RemoveTarget) + targetConfigController.GET("", targetconfig.ListTargetConfigs) + targetConfigController.POST("", targetconfig.CreateTargetConfig) + targetConfigController.DELETE("/:configId", targetconfig.DeleteTargetConfig) } logController := protected.Group("/log") { logController.GET("/server", log_controller.ReadServerLog) + + logController.GET("/target/:targetId", log_controller.ReadTargetLog) + logController.GET("/target/:targetId/write", log_controller.WriteTargetLog) + logController.GET("/workspace/:workspaceId", log_controller.ReadWorkspaceLog) - logController.GET("/workspace/:workspaceId/:projectName", log_controller.ReadProjectLog) + logController.GET("/workspace/:workspaceId/write", log_controller.WriteWorkspaceLog) + logController.GET("/build/:buildId", log_controller.ReadBuildLog) + logController.GET("/build/:buildId/write", log_controller.WriteBuildLog) + + logController.GET("/runner/:runnerId", log_controller.ReadRunnerLog) + logController.GET("/runner/:runnerId/write", log_controller.WriteRunnerLog) } gitProviderController := protected.Group("/gitprovider") { gitProviderController.GET("", gitprovider.ListGitProviders) - gitProviderController.PUT("", gitprovider.SetGitProvider) - gitProviderController.DELETE("/:gitProviderId", gitprovider.RemoveGitProvider) + gitProviderController.PUT("", gitprovider.SaveGitProvider) + gitProviderController.DELETE("/:gitProviderId", gitprovider.DeleteGitProvider) + gitProviderController.GET("/for-url/:url", gitprovider.ListGitProvidersForUrl) + gitProviderController.GET("/id-for-url/:url", gitprovider.FindGitProviderIdForUrl) + gitProviderController.GET("/:gitProviderId", gitprovider.FindGitProvider) + gitProviderController.GET("/:gitProviderId/user", gitprovider.GetGitUser) gitProviderController.GET("/:gitProviderId/namespaces", gitprovider.GetNamespaces) gitProviderController.GET("/:gitProviderId/:namespaceId/repositories", gitprovider.GetRepositories) @@ -296,23 +313,30 @@ func (a *ApiServer) Start() error { gitProviderController.GET("/:gitProviderId/:namespaceId/:repositoryId/pull-requests", gitprovider.GetRepoPRs) gitProviderController.POST("/context", gitprovider.GetGitContext) gitProviderController.POST("/context/url", gitprovider.GetUrlFromRepository) - gitProviderController.GET("/for-url/:url", gitprovider.ListGitProvidersForUrl) - gitProviderController.GET("/id-for-url/:url", gitprovider.GetGitProviderIdForUrl) - gitProviderController.GET("/:gitProviderId", gitprovider.GetGitProvider) } apiKeyController := protected.Group("/apikey") { apiKeyController.GET("", apikey.ListClientApiKeys) - apiKeyController.POST("/:apiKeyName", apikey.GenerateApiKey) - apiKeyController.DELETE("/:apiKeyName", apikey.RevokeApiKey) + apiKeyController.POST("/:apiKeyName", apikey.CreateApiKey) + apiKeyController.DELETE("/:apiKeyName", apikey.DeleteApiKey) + } + + envVarController := protected.Group("/env") + { + envVarController.GET("", env.ListEnvironmentVariables) + envVarController.PUT("", env.SaveEnvironmentVariable) + envVarController.DELETE("/:key", env.DeleteEnvironmentVariable) } - profileDataController := protected.Group("/profile") + containerRegistryController := protected.Group("/container-registry") { - profileDataController.GET("", profiledata.GetProfileData) - profileDataController.PUT("", profiledata.SetProfileData) - profileDataController.DELETE("", profiledata.DeleteProfileData) + containerRegistryController.GET("/:server", containerregistry.FindContainerRegistry) + } + + jobController := protected.Group("/job") + { + jobController.GET("", job.ListJobs) } samplesController := protected.Group("/sample") @@ -320,10 +344,47 @@ func (a *ApiServer) Start() error { samplesController.GET("", sample.ListSamples) } - projectGroup := protected.Group("/") - projectGroup.Use(middlewares.ProjectAuthMiddleware()) + runnerController := protected.Group("/runner") + { + // Defining the provider routes first to avoid conflicts with the runner routes + providerRoutePath := "/provider" + providersGroup := runnerController.Group(providerRoutePath) + { + providersGroup.GET("", provider.ListProviders) + providersGroup.GET("/for-install", provider.ListProvidersForInstall) + } + + runnerIdGroup := runnerController.Group(":runnerId") + { + runnerIdProviderGroup := runnerIdGroup.Group(providerRoutePath) + { + runnerIdProviderGroup.GET("", provider.GetRunnerProviders) + runnerIdProviderGroup.POST("/:providerName/install", provider.InstallProvider) + runnerIdProviderGroup.POST("/:providerName/uninstall", provider.UninstallProvider) + runnerIdProviderGroup.POST("/:providerName/update", provider.UpdateProvider) + } + + runnerIdGroup.GET("", runner.FindRunner) + runnerIdGroup.DELETE("", runner.DeleteRunner) + } + + runnerController.GET("", runner.ListRunners) + runnerController.POST("", runner.CreateRunner) + } + + workspaceGroup := protected.Group("/") + workspaceGroup.Use(middlewares.WorkspaceAuthMiddleware()) + { + workspaceGroup.POST(workspaceController.BasePath()+"/:workspaceId/metadata", workspace.UpdateWorkspaceMetadata) + workspaceGroup.POST(targetController.BasePath()+"/:targetId/metadata", target.UpdateTargetMetadata) + } + + runnerGroup := protected.Group("/") + runnerGroup.Use(middlewares.RunnerAuthMiddleware()) { - projectGroup.POST(workspaceController.BasePath()+"/:workspaceId/:projectId/state", workspace.SetProjectState) + runnerGroup.POST(runnerController.BasePath()+"/:runnerId/metadata", runner.UpdateRunnerMetadata) + runnerGroup.GET(runnerController.BasePath()+"/:runnerId/jobs", runner.ListRunnerJobs) + runnerGroup.POST(runnerController.BasePath()+"/:runnerId/jobs/:jobId/state", runner.UpdateJobState) } a.httpServer = &http.Server{ diff --git a/pkg/api/util/hide.go b/pkg/api/util/hide.go new file mode 100644 index 0000000000..34fb5046d3 --- /dev/null +++ b/pkg/api/util/hide.go @@ -0,0 +1,38 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package util + +import ( + "github.com/daytonaio/daytona/internal/util" + "github.com/daytonaio/daytona/pkg/gitprovider" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/server/targets" + "github.com/daytonaio/daytona/pkg/server/workspaces" +) + +func HideDaytonaEnvVars(envVars *map[string]string) { + for _, daytonaEnvVarKey := range getDaytonaEnvVarKeys() { + delete(*envVars, daytonaEnvVarKey) + } +} + +func getDaytonaEnvVarKeys() []string { + var result []string + + wsEnvVars := workspaces.GetWorkspaceEnvVars(&models.Workspace{ + Repository: &gitprovider.GitRepository{}, + }, workspaces.WorkspaceEnvVarParams{ + TelemetryEnabled: true, + }) + + targetEnvVars := targets.GetTargetEnvVars(&models.Target{}, targets.TargetEnvVarParams{}) + + envVars := util.MergeEnvVars(wsEnvVars, targetEnvVars) + + for k := range envVars { + result = append(result, k) + } + + return result +} diff --git a/pkg/api/util/token.go b/pkg/api/util/token.go new file mode 100644 index 0000000000..2e192fd2cb --- /dev/null +++ b/pkg/api/util/token.go @@ -0,0 +1,23 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package util + +import ( + "strings" + + "github.com/gin-gonic/gin" +) + +func ExtractToken(ctx *gin.Context) string { + bearerToken := ctx.GetHeader("Authorization") + if bearerToken == "" { + return "" + } + + if !strings.HasPrefix(bearerToken, "Bearer ") { + return "" + } + + return strings.TrimPrefix(bearerToken, "Bearer ") +} diff --git a/pkg/apiclient/README.md b/pkg/apiclient/README.md index 41fc0b9b3e..4c5c306203 100644 --- a/pkg/apiclient/README.md +++ b/pkg/apiclient/README.md @@ -77,23 +77,25 @@ All URIs are relative to *http://localhost:3986* Class | Method | HTTP request | Description ------------ | ------------- | ------------- | ------------- -*ApiKeyAPI* | [**GenerateApiKey**](docs/ApiKeyAPI.md#generateapikey) | **Post** /apikey/{apiKeyName} | Generate an API key +*ApiKeyAPI* | [**CreateApiKey**](docs/ApiKeyAPI.md#createapikey) | **Post** /apikey/{apiKeyName} | Create an API key +*ApiKeyAPI* | [**DeleteApiKey**](docs/ApiKeyAPI.md#deleteapikey) | **Delete** /apikey/{apiKeyName} | Delete API key *ApiKeyAPI* | [**ListClientApiKeys**](docs/ApiKeyAPI.md#listclientapikeys) | **Get** /apikey | List API keys -*ApiKeyAPI* | [**RevokeApiKey**](docs/ApiKeyAPI.md#revokeapikey) | **Delete** /apikey/{apiKeyName} | Revoke API key *BuildAPI* | [**CreateBuild**](docs/BuildAPI.md#createbuild) | **Post** /build | Create a build *BuildAPI* | [**DeleteAllBuilds**](docs/BuildAPI.md#deleteallbuilds) | **Delete** /build | Delete ALL builds *BuildAPI* | [**DeleteBuild**](docs/BuildAPI.md#deletebuild) | **Delete** /build/{buildId} | Delete build *BuildAPI* | [**DeleteBuildsFromPrebuild**](docs/BuildAPI.md#deletebuildsfromprebuild) | **Delete** /build/prebuild/{prebuildId} | Delete builds -*BuildAPI* | [**GetBuild**](docs/BuildAPI.md#getbuild) | **Get** /build/{buildId} | Get build data +*BuildAPI* | [**FindBuild**](docs/BuildAPI.md#findbuild) | **Get** /build/{buildId} | Find build *BuildAPI* | [**ListBuilds**](docs/BuildAPI.md#listbuilds) | **Get** /build | List builds -*ContainerRegistryAPI* | [**GetContainerRegistry**](docs/ContainerRegistryAPI.md#getcontainerregistry) | **Get** /container-registry/{server} | Get container registry credentials -*ContainerRegistryAPI* | [**ListContainerRegistries**](docs/ContainerRegistryAPI.md#listcontainerregistries) | **Get** /container-registry | List container registries -*ContainerRegistryAPI* | [**RemoveContainerRegistry**](docs/ContainerRegistryAPI.md#removecontainerregistry) | **Delete** /container-registry/{server} | Remove a container registry credentials -*ContainerRegistryAPI* | [**SetContainerRegistry**](docs/ContainerRegistryAPI.md#setcontainerregistry) | **Put** /container-registry/{server} | Set container registry credentials +*BuildAPI* | [**ListSuccessfulBuilds**](docs/BuildAPI.md#listsuccessfulbuilds) | **Get** /build/successful/{repoUrl} | List successful builds for Git repository +*ContainerRegistryAPI* | [**FindContainerRegistry**](docs/ContainerRegistryAPI.md#findcontainerregistry) | **Get** /container-registry/{server} | Find container registry *DefaultAPI* | [**HealthCheck**](docs/DefaultAPI.md#healthcheck) | **Get** /health | Health check +*EnvVarAPI* | [**DeleteEnvironmentVariable**](docs/EnvVarAPI.md#deleteenvironmentvariable) | **Delete** /env/{key} | Delete environment variable +*EnvVarAPI* | [**ListEnvironmentVariables**](docs/EnvVarAPI.md#listenvironmentvariables) | **Get** /env | List environment variables +*EnvVarAPI* | [**SaveEnvironmentVariable**](docs/EnvVarAPI.md#saveenvironmentvariable) | **Put** /env | Save environment variable +*GitProviderAPI* | [**DeleteGitProvider**](docs/GitProviderAPI.md#deletegitprovider) | **Delete** /gitprovider/{gitProviderId} | Delete Git provider +*GitProviderAPI* | [**FindGitProvider**](docs/GitProviderAPI.md#findgitprovider) | **Get** /gitprovider/{gitProviderId} | Find Git provider +*GitProviderAPI* | [**FindGitProviderIdForUrl**](docs/GitProviderAPI.md#findgitprovideridforurl) | **Get** /gitprovider/id-for-url/{url} | Find Git provider ID *GitProviderAPI* | [**GetGitContext**](docs/GitProviderAPI.md#getgitcontext) | **Post** /gitprovider/context | Get Git context -*GitProviderAPI* | [**GetGitProvider**](docs/GitProviderAPI.md#getgitprovider) | **Get** /gitprovider/{gitProviderId} | Get Git provider -*GitProviderAPI* | [**GetGitProviderIdForUrl**](docs/GitProviderAPI.md#getgitprovideridforurl) | **Get** /gitprovider/id-for-url/{url} | Get Git provider ID *GitProviderAPI* | [**GetGitUser**](docs/GitProviderAPI.md#getgituser) | **Get** /gitprovider/{gitProviderId}/user | Get Git context *GitProviderAPI* | [**GetNamespaces**](docs/GitProviderAPI.md#getnamespaces) | **Get** /gitprovider/{gitProviderId}/namespaces | Get Git namespaces *GitProviderAPI* | [**GetRepoBranches**](docs/GitProviderAPI.md#getrepobranches) | **Get** /gitprovider/{gitProviderId}/{namespaceId}/{repositoryId}/branches | Get Git repository branches @@ -102,88 +104,105 @@ Class | Method | HTTP request | Description *GitProviderAPI* | [**GetUrlFromRepository**](docs/GitProviderAPI.md#geturlfromrepository) | **Post** /gitprovider/context/url | Get URL from Git repository *GitProviderAPI* | [**ListGitProviders**](docs/GitProviderAPI.md#listgitproviders) | **Get** /gitprovider | List Git providers *GitProviderAPI* | [**ListGitProvidersForUrl**](docs/GitProviderAPI.md#listgitprovidersforurl) | **Get** /gitprovider/for-url/{url} | List Git providers for url -*GitProviderAPI* | [**RemoveGitProvider**](docs/GitProviderAPI.md#removegitprovider) | **Delete** /gitprovider/{gitProviderId} | Remove Git provider -*GitProviderAPI* | [**SetGitProvider**](docs/GitProviderAPI.md#setgitprovider) | **Put** /gitprovider | Set Git provider -*PrebuildAPI* | [**DeletePrebuild**](docs/PrebuildAPI.md#deleteprebuild) | **Delete** /project-config/{configName}/prebuild/{prebuildId} | Delete prebuild -*PrebuildAPI* | [**GetPrebuild**](docs/PrebuildAPI.md#getprebuild) | **Get** /project-config/{configName}/prebuild/{prebuildId} | Get prebuild -*PrebuildAPI* | [**ListPrebuilds**](docs/PrebuildAPI.md#listprebuilds) | **Get** /project-config/prebuild | List prebuilds -*PrebuildAPI* | [**ListPrebuildsForProjectConfig**](docs/PrebuildAPI.md#listprebuildsforprojectconfig) | **Get** /project-config/{configName}/prebuild | List prebuilds for project config -*PrebuildAPI* | [**ProcessGitEvent**](docs/PrebuildAPI.md#processgitevent) | **Post** /project-config/prebuild/process-git-event | ProcessGitEvent -*PrebuildAPI* | [**SetPrebuild**](docs/PrebuildAPI.md#setprebuild) | **Put** /project-config/{configName}/prebuild | Set prebuild -*ProfileAPI* | [**DeleteProfileData**](docs/ProfileAPI.md#deleteprofiledata) | **Delete** /profile | Delete profile data -*ProfileAPI* | [**GetProfileData**](docs/ProfileAPI.md#getprofiledata) | **Get** /profile | Get profile data -*ProfileAPI* | [**SetProfileData**](docs/ProfileAPI.md#setprofiledata) | **Put** /profile | Set profile data -*ProjectConfigAPI* | [**DeleteProjectConfig**](docs/ProjectConfigAPI.md#deleteprojectconfig) | **Delete** /project-config/{configName} | Delete project config data -*ProjectConfigAPI* | [**GetDefaultProjectConfig**](docs/ProjectConfigAPI.md#getdefaultprojectconfig) | **Get** /project-config/default/{gitUrl} | Get project configs by git url -*ProjectConfigAPI* | [**GetProjectConfig**](docs/ProjectConfigAPI.md#getprojectconfig) | **Get** /project-config/{configName} | Get project config data -*ProjectConfigAPI* | [**ListProjectConfigs**](docs/ProjectConfigAPI.md#listprojectconfigs) | **Get** /project-config | List project configs -*ProjectConfigAPI* | [**SetDefaultProjectConfig**](docs/ProjectConfigAPI.md#setdefaultprojectconfig) | **Patch** /project-config/{configName}/set-default | Set project config to default -*ProjectConfigAPI* | [**SetProjectConfig**](docs/ProjectConfigAPI.md#setprojectconfig) | **Put** /project-config | Set project config data -*ProviderAPI* | [**GetTargetManifest**](docs/ProviderAPI.md#gettargetmanifest) | **Get** /provider/{provider}/target-manifest | Get provider target manifest -*ProviderAPI* | [**InstallProvider**](docs/ProviderAPI.md#installprovider) | **Post** /provider/install | Install a provider -*ProviderAPI* | [**ListProviders**](docs/ProviderAPI.md#listproviders) | **Get** /provider | List providers -*ProviderAPI* | [**UninstallProvider**](docs/ProviderAPI.md#uninstallprovider) | **Post** /provider/{provider}/uninstall | Uninstall a provider +*GitProviderAPI* | [**SaveGitProvider**](docs/GitProviderAPI.md#savegitprovider) | **Put** /gitprovider | Save Git provider +*JobAPI* | [**ListJobs**](docs/JobAPI.md#listjobs) | **Get** /job | List jobs +*PrebuildAPI* | [**DeletePrebuild**](docs/PrebuildAPI.md#deleteprebuild) | **Delete** /workspace-template/{templateName}/prebuild/{prebuildId} | Delete prebuild +*PrebuildAPI* | [**FindPrebuild**](docs/PrebuildAPI.md#findprebuild) | **Get** /workspace-template/{templateName}/prebuild/{prebuildId} | Find prebuild +*PrebuildAPI* | [**ListPrebuilds**](docs/PrebuildAPI.md#listprebuilds) | **Get** /workspace-template/prebuild | List prebuilds +*PrebuildAPI* | [**ListPrebuildsForWorkspaceTemplate**](docs/PrebuildAPI.md#listprebuildsforworkspacetemplate) | **Get** /workspace-template/{templateName}/prebuild | List prebuilds for workspace template +*PrebuildAPI* | [**ProcessGitEvent**](docs/PrebuildAPI.md#processgitevent) | **Post** /workspace-template/prebuild/process-git-event | ProcessGitEvent +*PrebuildAPI* | [**SavePrebuild**](docs/PrebuildAPI.md#saveprebuild) | **Put** /workspace-template/{templateName}/prebuild | Save prebuild +*ProviderAPI* | [**GetRunnerProviders**](docs/ProviderAPI.md#getrunnerproviders) | **Get** /runner/{runnerId}/provider | Get runner providers +*ProviderAPI* | [**InstallProvider**](docs/ProviderAPI.md#installprovider) | **Post** /runner/{runnerId}/provider/{providerName}/install | Install provider +*ProviderAPI* | [**ListProviders**](docs/ProviderAPI.md#listproviders) | **Get** /runner/provider | List providers +*ProviderAPI* | [**ListProvidersForInstall**](docs/ProviderAPI.md#listprovidersforinstall) | **Get** /runner/provider/for-install | List providers available for installation +*ProviderAPI* | [**UninstallProvider**](docs/ProviderAPI.md#uninstallprovider) | **Post** /runner/{runnerId}/provider/{providerName}/uninstall | Uninstall provider +*ProviderAPI* | [**UpdateProvider**](docs/ProviderAPI.md#updateprovider) | **Post** /runner/{runnerId}/provider/{providerName}/update | Update provider +*RunnerAPI* | [**CreateRunner**](docs/RunnerAPI.md#createrunner) | **Post** /runner | Create a runner +*RunnerAPI* | [**DeleteRunner**](docs/RunnerAPI.md#deleterunner) | **Delete** /runner/{runnerId} | Delete runner +*RunnerAPI* | [**FindRunner**](docs/RunnerAPI.md#findrunner) | **Get** /runner/{runnerId} | Find a runner +*RunnerAPI* | [**ListRunnerJobs**](docs/RunnerAPI.md#listrunnerjobs) | **Get** /runner/{runnerId}/jobs | List runner jobs +*RunnerAPI* | [**ListRunners**](docs/RunnerAPI.md#listrunners) | **Get** /runner | List runners +*RunnerAPI* | [**UpdateJobState**](docs/RunnerAPI.md#updatejobstate) | **Post** /runner/{runnerId}/jobs/{jobId}/state | Update job state +*RunnerAPI* | [**UpdateRunnerMetadata**](docs/RunnerAPI.md#updaterunnermetadata) | **Post** /runner/{runnerId}/metadata | Update runner metadata *SampleAPI* | [**ListSamples**](docs/SampleAPI.md#listsamples) | **Get** /sample | List samples -*ServerAPI* | [**GenerateNetworkKey**](docs/ServerAPI.md#generatenetworkkey) | **Post** /server/network-key | Generate a new authentication key +*ServerAPI* | [**CreateNetworkKey**](docs/ServerAPI.md#createnetworkkey) | **Post** /server/network-key | Create a new authentication key *ServerAPI* | [**GetConfig**](docs/ServerAPI.md#getconfig) | **Get** /server/config | Get the server configuration -*ServerAPI* | [**GetServerLogFiles**](docs/ServerAPI.md#getserverlogfiles) | **Get** /server/logs | List server log files -*ServerAPI* | [**SetConfig**](docs/ServerAPI.md#setconfig) | **Post** /server/config | Set the server configuration +*ServerAPI* | [**GetServerLogFiles**](docs/ServerAPI.md#getserverlogfiles) | **Get** /server/logs | Get server log files +*ServerAPI* | [**SaveConfig**](docs/ServerAPI.md#saveconfig) | **Put** /server/config | Save the server configuration +*TargetAPI* | [**CreateTarget**](docs/TargetAPI.md#createtarget) | **Post** /target | Create a target +*TargetAPI* | [**DeleteTarget**](docs/TargetAPI.md#deletetarget) | **Delete** /target/{targetId} | Delete target +*TargetAPI* | [**FindTarget**](docs/TargetAPI.md#findtarget) | **Get** /target/{targetId} | Find target +*TargetAPI* | [**GetTargetState**](docs/TargetAPI.md#gettargetstate) | **Get** /target/{targetId}/state | Get target state +*TargetAPI* | [**HandleSuccessfulCreation**](docs/TargetAPI.md#handlesuccessfulcreation) | **Post** /target/{targetId}/handle-successful-creation | Handles successful creation of the target *TargetAPI* | [**ListTargets**](docs/TargetAPI.md#listtargets) | **Get** /target | List targets -*TargetAPI* | [**RemoveTarget**](docs/TargetAPI.md#removetarget) | **Delete** /target/{target} | Remove a target -*TargetAPI* | [**SetDefaultTarget**](docs/TargetAPI.md#setdefaulttarget) | **Patch** /target/{target}/set-default | Set target to default -*TargetAPI* | [**SetTarget**](docs/TargetAPI.md#settarget) | **Put** /target | Set a target +*TargetAPI* | [**RestartTarget**](docs/TargetAPI.md#restarttarget) | **Post** /target/{targetId}/restart | Restart target +*TargetAPI* | [**SetDefaultTarget**](docs/TargetAPI.md#setdefaulttarget) | **Patch** /target/{targetId}/set-default | Set target to be used by default +*TargetAPI* | [**StartTarget**](docs/TargetAPI.md#starttarget) | **Post** /target/{targetId}/start | Start target +*TargetAPI* | [**StopTarget**](docs/TargetAPI.md#stoptarget) | **Post** /target/{targetId}/stop | Stop target +*TargetAPI* | [**UpdateTargetMetadata**](docs/TargetAPI.md#updatetargetmetadata) | **Post** /target/{targetId}/metadata | Update target metadata +*TargetAPI* | [**UpdateTargetProviderMetadata**](docs/TargetAPI.md#updatetargetprovidermetadata) | **Post** /target/{targetId}/provider-metadata | Update target provider metadata +*TargetConfigAPI* | [**CreateTargetConfig**](docs/TargetConfigAPI.md#createtargetconfig) | **Post** /target-config | Create a target config +*TargetConfigAPI* | [**DeleteTargetConfig**](docs/TargetConfigAPI.md#deletetargetconfig) | **Delete** /target-config/{configId} | Delete a target config +*TargetConfigAPI* | [**ListTargetConfigs**](docs/TargetConfigAPI.md#listtargetconfigs) | **Get** /target-config | List target configs *WorkspaceAPI* | [**CreateWorkspace**](docs/WorkspaceAPI.md#createworkspace) | **Post** /workspace | Create a workspace -*WorkspaceAPI* | [**GetWorkspace**](docs/WorkspaceAPI.md#getworkspace) | **Get** /workspace/{workspaceId} | Get workspace info +*WorkspaceAPI* | [**DeleteWorkspace**](docs/WorkspaceAPI.md#deleteworkspace) | **Delete** /workspace/{workspaceId} | Delete workspace +*WorkspaceAPI* | [**FindWorkspace**](docs/WorkspaceAPI.md#findworkspace) | **Get** /workspace/{workspaceId} | Find workspace +*WorkspaceAPI* | [**GetWorkspaceState**](docs/WorkspaceAPI.md#getworkspacestate) | **Get** /workspace/{workspaceId}/state | Get workspace state *WorkspaceAPI* | [**ListWorkspaces**](docs/WorkspaceAPI.md#listworkspaces) | **Get** /workspace | List workspaces -*WorkspaceAPI* | [**RemoveWorkspace**](docs/WorkspaceAPI.md#removeworkspace) | **Delete** /workspace/{workspaceId} | Remove workspace -*WorkspaceAPI* | [**SetProjectState**](docs/WorkspaceAPI.md#setprojectstate) | **Post** /workspace/{workspaceId}/{projectId}/state | Set project state -*WorkspaceAPI* | [**StartProject**](docs/WorkspaceAPI.md#startproject) | **Post** /workspace/{workspaceId}/{projectId}/start | Start project +*WorkspaceAPI* | [**RestartWorkspace**](docs/WorkspaceAPI.md#restartworkspace) | **Post** /workspace/{workspaceId}/restart | Restart workspace *WorkspaceAPI* | [**StartWorkspace**](docs/WorkspaceAPI.md#startworkspace) | **Post** /workspace/{workspaceId}/start | Start workspace -*WorkspaceAPI* | [**StopProject**](docs/WorkspaceAPI.md#stopproject) | **Post** /workspace/{workspaceId}/{projectId}/stop | Stop project *WorkspaceAPI* | [**StopWorkspace**](docs/WorkspaceAPI.md#stopworkspace) | **Post** /workspace/{workspaceId}/stop | Stop workspace -*WorkspaceToolboxAPI* | [**CreateSession**](docs/WorkspaceToolboxAPI.md#createsession) | **Post** /workspace/{workspaceId}/{projectId}/toolbox/process/session | Create exec session -*WorkspaceToolboxAPI* | [**DeleteSession**](docs/WorkspaceToolboxAPI.md#deletesession) | **Delete** /workspace/{workspaceId}/{projectId}/toolbox/process/session/{sessionId} | Delete session -*WorkspaceToolboxAPI* | [**FsCreateFolder**](docs/WorkspaceToolboxAPI.md#fscreatefolder) | **Post** /workspace/{workspaceId}/{projectId}/toolbox/files/folder | Create folder -*WorkspaceToolboxAPI* | [**FsDeleteFile**](docs/WorkspaceToolboxAPI.md#fsdeletefile) | **Delete** /workspace/{workspaceId}/{projectId}/toolbox/files | Delete file -*WorkspaceToolboxAPI* | [**FsDownloadFile**](docs/WorkspaceToolboxAPI.md#fsdownloadfile) | **Get** /workspace/{workspaceId}/{projectId}/toolbox/files/download | Download file -*WorkspaceToolboxAPI* | [**FsFindInFiles**](docs/WorkspaceToolboxAPI.md#fsfindinfiles) | **Get** /workspace/{workspaceId}/{projectId}/toolbox/files/find | Search for text/pattern in files -*WorkspaceToolboxAPI* | [**FsGetFileDetails**](docs/WorkspaceToolboxAPI.md#fsgetfiledetails) | **Get** /workspace/{workspaceId}/{projectId}/toolbox/files/info | Get file info -*WorkspaceToolboxAPI* | [**FsListFiles**](docs/WorkspaceToolboxAPI.md#fslistfiles) | **Get** /workspace/{workspaceId}/{projectId}/toolbox/files | List files -*WorkspaceToolboxAPI* | [**FsMoveFile**](docs/WorkspaceToolboxAPI.md#fsmovefile) | **Post** /workspace/{workspaceId}/{projectId}/toolbox/files/move | Create folder -*WorkspaceToolboxAPI* | [**FsReplaceInFiles**](docs/WorkspaceToolboxAPI.md#fsreplaceinfiles) | **Post** /workspace/{workspaceId}/{projectId}/toolbox/files/replace | Repleace text/pattern in files -*WorkspaceToolboxAPI* | [**FsSearchFiles**](docs/WorkspaceToolboxAPI.md#fssearchfiles) | **Get** /workspace/{workspaceId}/{projectId}/toolbox/files/search | Search for files -*WorkspaceToolboxAPI* | [**FsSetFilePermissions**](docs/WorkspaceToolboxAPI.md#fssetfilepermissions) | **Post** /workspace/{workspaceId}/{projectId}/toolbox/files/permissions | Set file owner/group/permissions -*WorkspaceToolboxAPI* | [**FsUploadFile**](docs/WorkspaceToolboxAPI.md#fsuploadfile) | **Post** /workspace/{workspaceId}/{projectId}/toolbox/files/upload | Upload file -*WorkspaceToolboxAPI* | [**GetProjectDir**](docs/WorkspaceToolboxAPI.md#getprojectdir) | **Get** /workspace/{workspaceId}/{projectId}/toolbox/project-dir | Get project dir -*WorkspaceToolboxAPI* | [**GetSessionCommandLogs**](docs/WorkspaceToolboxAPI.md#getsessioncommandlogs) | **Get** /workspace/{workspaceId}/{projectId}/toolbox/process/session/{sessionId}/command/{commandId}/logs | Get session command logs -*WorkspaceToolboxAPI* | [**GitAddFiles**](docs/WorkspaceToolboxAPI.md#gitaddfiles) | **Post** /workspace/{workspaceId}/{projectId}/toolbox/git/add | Add files -*WorkspaceToolboxAPI* | [**GitBranchList**](docs/WorkspaceToolboxAPI.md#gitbranchlist) | **Get** /workspace/{workspaceId}/{projectId}/toolbox/git/branches | Get branch list -*WorkspaceToolboxAPI* | [**GitCloneRepository**](docs/WorkspaceToolboxAPI.md#gitclonerepository) | **Post** /workspace/{workspaceId}/{projectId}/toolbox/git/clone | Clone git repository -*WorkspaceToolboxAPI* | [**GitCommitChanges**](docs/WorkspaceToolboxAPI.md#gitcommitchanges) | **Post** /workspace/{workspaceId}/{projectId}/toolbox/git/commit | Commit changes -*WorkspaceToolboxAPI* | [**GitCommitHistory**](docs/WorkspaceToolboxAPI.md#gitcommithistory) | **Get** /workspace/{workspaceId}/{projectId}/toolbox/git/history | Get commit history -*WorkspaceToolboxAPI* | [**GitCreateBranch**](docs/WorkspaceToolboxAPI.md#gitcreatebranch) | **Post** /workspace/{workspaceId}/{projectId}/toolbox/git/branches | Create branch -*WorkspaceToolboxAPI* | [**GitGitStatus**](docs/WorkspaceToolboxAPI.md#gitgitstatus) | **Get** /workspace/{workspaceId}/{projectId}/toolbox/git/status | Get git status -*WorkspaceToolboxAPI* | [**GitPullChanges**](docs/WorkspaceToolboxAPI.md#gitpullchanges) | **Post** /workspace/{workspaceId}/{projectId}/toolbox/git/pull | Pull changes -*WorkspaceToolboxAPI* | [**GitPushChanges**](docs/WorkspaceToolboxAPI.md#gitpushchanges) | **Post** /workspace/{workspaceId}/{projectId}/toolbox/git/push | Push changes -*WorkspaceToolboxAPI* | [**ListSessions**](docs/WorkspaceToolboxAPI.md#listsessions) | **Get** /workspace/{workspaceId}/{projectId}/toolbox/process/session | List sessions -*WorkspaceToolboxAPI* | [**LspCompletions**](docs/WorkspaceToolboxAPI.md#lspcompletions) | **Post** /workspace/{workspaceId}/{projectId}/toolbox/lsp/completions | Get Lsp Completions -*WorkspaceToolboxAPI* | [**LspDidClose**](docs/WorkspaceToolboxAPI.md#lspdidclose) | **Post** /workspace/{workspaceId}/{projectId}/toolbox/lsp/did-close | Call Lsp DidClose -*WorkspaceToolboxAPI* | [**LspDidOpen**](docs/WorkspaceToolboxAPI.md#lspdidopen) | **Post** /workspace/{workspaceId}/{projectId}/toolbox/lsp/did-open | Call Lsp DidOpen -*WorkspaceToolboxAPI* | [**LspDocumentSymbols**](docs/WorkspaceToolboxAPI.md#lspdocumentsymbols) | **Get** /workspace/{workspaceId}/{projectId}/toolbox/lsp/document-symbols | Call Lsp DocumentSymbols -*WorkspaceToolboxAPI* | [**LspStart**](docs/WorkspaceToolboxAPI.md#lspstart) | **Post** /workspace/{workspaceId}/{projectId}/toolbox/lsp/start | Start Lsp server -*WorkspaceToolboxAPI* | [**LspStop**](docs/WorkspaceToolboxAPI.md#lspstop) | **Post** /workspace/{workspaceId}/{projectId}/toolbox/lsp/stop | Stop Lsp server -*WorkspaceToolboxAPI* | [**LspWorkspaceSymbols**](docs/WorkspaceToolboxAPI.md#lspworkspacesymbols) | **Get** /workspace/{workspaceId}/{projectId}/toolbox/lsp/workspace-symbols | Call Lsp WorkspaceSymbols -*WorkspaceToolboxAPI* | [**ProcessExecuteCommand**](docs/WorkspaceToolboxAPI.md#processexecutecommand) | **Post** /workspace/{workspaceId}/{projectId}/toolbox/process/execute | Execute command -*WorkspaceToolboxAPI* | [**SessionExecuteCommand**](docs/WorkspaceToolboxAPI.md#sessionexecutecommand) | **Post** /workspace/{workspaceId}/{projectId}/toolbox/process/session/{sessionId}/exec | Execute command in session +*WorkspaceAPI* | [**UpdateWorkspaceLabels**](docs/WorkspaceAPI.md#updateworkspacelabels) | **Post** /workspace/{workspaceId}/labels | Update workspace labels +*WorkspaceAPI* | [**UpdateWorkspaceMetadata**](docs/WorkspaceAPI.md#updateworkspacemetadata) | **Post** /workspace/{workspaceId}/metadata | Update workspace metadata +*WorkspaceAPI* | [**UpdateWorkspaceProviderMetadata**](docs/WorkspaceAPI.md#updateworkspaceprovidermetadata) | **Post** /workspace/{workspaceId}/provider-metadata | Update workspace provider metadata +*WorkspaceTemplateAPI* | [**DeleteWorkspaceTemplate**](docs/WorkspaceTemplateAPI.md#deleteworkspacetemplate) | **Delete** /workspace-template/{templateName} | Delete workspace template data +*WorkspaceTemplateAPI* | [**FindWorkspaceTemplate**](docs/WorkspaceTemplateAPI.md#findworkspacetemplate) | **Get** /workspace-template/{templateName} | Find a workspace template +*WorkspaceTemplateAPI* | [**GetDefaultWorkspaceTemplate**](docs/WorkspaceTemplateAPI.md#getdefaultworkspacetemplate) | **Get** /workspace-template/default/{gitUrl} | Get default workspace templates by git url +*WorkspaceTemplateAPI* | [**ListWorkspaceTemplates**](docs/WorkspaceTemplateAPI.md#listworkspacetemplates) | **Get** /workspace-template | List workspace templates +*WorkspaceTemplateAPI* | [**SaveWorkspaceTemplate**](docs/WorkspaceTemplateAPI.md#saveworkspacetemplate) | **Put** /workspace-template | Set workspace template data +*WorkspaceTemplateAPI* | [**SetDefaultWorkspaceTemplate**](docs/WorkspaceTemplateAPI.md#setdefaultworkspacetemplate) | **Patch** /workspace-template/{templateName}/set-default | Set workspace template to default +*WorkspaceToolboxAPI* | [**CreateSession**](docs/WorkspaceToolboxAPI.md#createsession) | **Post** /workspace/{workspaceId}/toolbox/process/session | Create exec session +*WorkspaceToolboxAPI* | [**DeleteSession**](docs/WorkspaceToolboxAPI.md#deletesession) | **Delete** /workspace/{workspaceId}/toolbox/process/session/{sessionId} | Delete session +*WorkspaceToolboxAPI* | [**FsCreateFolder**](docs/WorkspaceToolboxAPI.md#fscreatefolder) | **Post** /workspace/{workspaceId}/toolbox/files/folder | Create folder +*WorkspaceToolboxAPI* | [**FsDeleteFile**](docs/WorkspaceToolboxAPI.md#fsdeletefile) | **Delete** /workspace/{workspaceId}/toolbox/files | Delete file +*WorkspaceToolboxAPI* | [**FsDownloadFile**](docs/WorkspaceToolboxAPI.md#fsdownloadfile) | **Get** /workspace/{workspaceId}/toolbox/files/download | Download file +*WorkspaceToolboxAPI* | [**FsFindInFiles**](docs/WorkspaceToolboxAPI.md#fsfindinfiles) | **Get** /workspace/{workspaceId}/toolbox/files/find | Search for text/pattern in files +*WorkspaceToolboxAPI* | [**FsGetFileDetails**](docs/WorkspaceToolboxAPI.md#fsgetfiledetails) | **Get** /workspace/{workspaceId}/toolbox/files/info | Get file info +*WorkspaceToolboxAPI* | [**FsListFiles**](docs/WorkspaceToolboxAPI.md#fslistfiles) | **Get** /workspace/{workspaceId}/toolbox/files | List files +*WorkspaceToolboxAPI* | [**FsMoveFile**](docs/WorkspaceToolboxAPI.md#fsmovefile) | **Post** /workspace/{workspaceId}/toolbox/files/move | Create folder +*WorkspaceToolboxAPI* | [**FsReplaceInFiles**](docs/WorkspaceToolboxAPI.md#fsreplaceinfiles) | **Post** /workspace/{workspaceId}/toolbox/files/replace | Repleace text/pattern in files +*WorkspaceToolboxAPI* | [**FsSearchFiles**](docs/WorkspaceToolboxAPI.md#fssearchfiles) | **Get** /workspace/{workspaceId}/toolbox/files/search | Search for files +*WorkspaceToolboxAPI* | [**FsSetFilePermissions**](docs/WorkspaceToolboxAPI.md#fssetfilepermissions) | **Post** /workspace/{workspaceId}/toolbox/files/permissions | Set file owner/group/permissions +*WorkspaceToolboxAPI* | [**FsUploadFile**](docs/WorkspaceToolboxAPI.md#fsuploadfile) | **Post** /workspace/{workspaceId}/toolbox/files/upload | Upload file +*WorkspaceToolboxAPI* | [**GetSessionCommandLogs**](docs/WorkspaceToolboxAPI.md#getsessioncommandlogs) | **Get** /workspace/{workspaceId}/toolbox/process/session/{sessionId}/command/{commandId}/logs | Get session command logs +*WorkspaceToolboxAPI* | [**GetWorkspaceDir**](docs/WorkspaceToolboxAPI.md#getworkspacedir) | **Get** /workspace/{workspaceId}/toolbox/workspace-dir | Get workspace dir +*WorkspaceToolboxAPI* | [**GitAddFiles**](docs/WorkspaceToolboxAPI.md#gitaddfiles) | **Post** /workspace/{workspaceId}/toolbox/git/add | Add files +*WorkspaceToolboxAPI* | [**GitBranchList**](docs/WorkspaceToolboxAPI.md#gitbranchlist) | **Get** /workspace/{workspaceId}/toolbox/git/branches | Get branch list +*WorkspaceToolboxAPI* | [**GitCloneRepository**](docs/WorkspaceToolboxAPI.md#gitclonerepository) | **Post** /workspace/{workspaceId}/toolbox/git/clone | Clone git repository +*WorkspaceToolboxAPI* | [**GitCommitChanges**](docs/WorkspaceToolboxAPI.md#gitcommitchanges) | **Post** /workspace/{workspaceId}/toolbox/git/commit | Commit changes +*WorkspaceToolboxAPI* | [**GitCommitHistory**](docs/WorkspaceToolboxAPI.md#gitcommithistory) | **Get** /workspace/{workspaceId}/toolbox/git/history | Get commit history +*WorkspaceToolboxAPI* | [**GitCreateBranch**](docs/WorkspaceToolboxAPI.md#gitcreatebranch) | **Post** /workspace/{workspaceId}/toolbox/git/branches | Create branch +*WorkspaceToolboxAPI* | [**GitGitStatus**](docs/WorkspaceToolboxAPI.md#gitgitstatus) | **Get** /workspace/{workspaceId}/toolbox/git/status | Get git status +*WorkspaceToolboxAPI* | [**GitPullChanges**](docs/WorkspaceToolboxAPI.md#gitpullchanges) | **Post** /workspace/{workspaceId}/toolbox/git/pull | Pull changes +*WorkspaceToolboxAPI* | [**GitPushChanges**](docs/WorkspaceToolboxAPI.md#gitpushchanges) | **Post** /workspace/{workspaceId}/toolbox/git/push | Push changes +*WorkspaceToolboxAPI* | [**ListSessions**](docs/WorkspaceToolboxAPI.md#listsessions) | **Get** /workspace/{workspaceId}/toolbox/process/session | List sessions +*WorkspaceToolboxAPI* | [**LspCompletions**](docs/WorkspaceToolboxAPI.md#lspcompletions) | **Post** /workspace/{workspaceId}/toolbox/lsp/completions | Get Lsp Completions +*WorkspaceToolboxAPI* | [**LspDidClose**](docs/WorkspaceToolboxAPI.md#lspdidclose) | **Post** /workspace/{workspaceId}/toolbox/lsp/did-close | Call Lsp DidClose +*WorkspaceToolboxAPI* | [**LspDidOpen**](docs/WorkspaceToolboxAPI.md#lspdidopen) | **Post** /workspace/{workspaceId}/toolbox/lsp/did-open | Call Lsp DidOpen +*WorkspaceToolboxAPI* | [**LspDocumentSymbols**](docs/WorkspaceToolboxAPI.md#lspdocumentsymbols) | **Get** /workspace/{workspaceId}/toolbox/lsp/document-symbols | Call Lsp DocumentSymbols +*WorkspaceToolboxAPI* | [**LspStart**](docs/WorkspaceToolboxAPI.md#lspstart) | **Post** /workspace/{workspaceId}/toolbox/lsp/start | Start Lsp server +*WorkspaceToolboxAPI* | [**LspStop**](docs/WorkspaceToolboxAPI.md#lspstop) | **Post** /workspace/{workspaceId}/toolbox/lsp/stop | Stop Lsp server +*WorkspaceToolboxAPI* | [**LspWorkspaceSymbols**](docs/WorkspaceToolboxAPI.md#lspworkspacesymbols) | **Get** /workspace/{workspaceId}/toolbox/lsp/workspace-symbols | Call Lsp WorkspaceSymbols +*WorkspaceToolboxAPI* | [**ProcessExecuteCommand**](docs/WorkspaceToolboxAPI.md#processexecutecommand) | **Post** /workspace/{workspaceId}/toolbox/process/execute | Execute command +*WorkspaceToolboxAPI* | [**SessionExecuteCommand**](docs/WorkspaceToolboxAPI.md#sessionexecutecommand) | **Post** /workspace/{workspaceId}/toolbox/process/session/{sessionId}/exec | Execute command in session ## Documentation For Models - - [ApiKey](docs/ApiKey.md) - - [ApikeyApiKeyType](docs/ApikeyApiKeyType.md) - - [Build](docs/Build.md) - - [BuildBuildState](docs/BuildBuildState.md) + - [ApiKeyViewDTO](docs/ApiKeyViewDTO.md) - [BuildConfig](docs/BuildConfig.md) + - [BuildDTO](docs/BuildDTO.md) - [CachedBuild](docs/CachedBuild.md) - [CloneTarget](docs/CloneTarget.md) - [Command](docs/Command.md) @@ -194,13 +213,16 @@ Class | Method | HTTP request | Description - [ContainerRegistry](docs/ContainerRegistry.md) - [CreateBuildDTO](docs/CreateBuildDTO.md) - [CreatePrebuildDTO](docs/CreatePrebuildDTO.md) - - [CreateProjectConfigDTO](docs/CreateProjectConfigDTO.md) - - [CreateProjectDTO](docs/CreateProjectDTO.md) - - [CreateProjectSourceDTO](docs/CreateProjectSourceDTO.md) - - [CreateProviderTargetDTO](docs/CreateProviderTargetDTO.md) + - [CreateRunnerDTO](docs/CreateRunnerDTO.md) + - [CreateRunnerResultDTO](docs/CreateRunnerResultDTO.md) - [CreateSessionRequest](docs/CreateSessionRequest.md) + - [CreateTargetConfigDTO](docs/CreateTargetConfigDTO.md) + - [CreateTargetDTO](docs/CreateTargetDTO.md) - [CreateWorkspaceDTO](docs/CreateWorkspaceDTO.md) + - [CreateWorkspaceSourceDTO](docs/CreateWorkspaceSourceDTO.md) + - [CreateWorkspaceTemplateDTO](docs/CreateWorkspaceTemplateDTO.md) - [DevcontainerConfig](docs/DevcontainerConfig.md) + - [EnvironmentVariable](docs/EnvironmentVariable.md) - [ExecuteRequest](docs/ExecuteRequest.md) - [ExecuteResponse](docs/ExecuteResponse.md) - [FRPSConfig](docs/FRPSConfig.md) @@ -221,7 +243,8 @@ Class | Method | HTTP request | Description - [GitRepository](docs/GitRepository.md) - [GitStatus](docs/GitStatus.md) - [GitUser](docs/GitUser.md) - - [InstallProviderRequest](docs/InstallProviderRequest.md) + - [Job](docs/Job.md) + - [JobState](docs/JobState.md) - [ListBranchResponse](docs/ListBranchResponse.md) - [LogFileConfig](docs/LogFileConfig.md) - [LspCompletionParams](docs/LspCompletionParams.md) @@ -232,24 +255,23 @@ Class | Method | HTTP request | Description - [LspServerRequest](docs/LspServerRequest.md) - [LspSymbol](docs/LspSymbol.md) - [Match](docs/Match.md) + - [ModelsApiKeyType](docs/ModelsApiKeyType.md) + - [ModelsJobAction](docs/ModelsJobAction.md) + - [ModelsResourceStateName](docs/ModelsResourceStateName.md) + - [ModelsTargetConfigPropertyType](docs/ModelsTargetConfigPropertyType.md) - [NetworkKey](docs/NetworkKey.md) - [Position](docs/Position.md) - [PrebuildConfig](docs/PrebuildConfig.md) - [PrebuildDTO](docs/PrebuildDTO.md) - - [ProfileData](docs/ProfileData.md) - - [Project](docs/Project.md) - - [ProjectConfig](docs/ProjectConfig.md) - - [ProjectDirResponse](docs/ProjectDirResponse.md) - - [ProjectInfo](docs/ProjectInfo.md) - - [ProjectState](docs/ProjectState.md) - - [Provider](docs/Provider.md) - - [ProviderProviderInfo](docs/ProviderProviderInfo.md) - - [ProviderProviderTargetProperty](docs/ProviderProviderTargetProperty.md) - - [ProviderProviderTargetPropertyType](docs/ProviderProviderTargetPropertyType.md) - - [ProviderTarget](docs/ProviderTarget.md) + - [ProviderDTO](docs/ProviderDTO.md) + - [ProviderInfo](docs/ProviderInfo.md) - [ReplaceRequest](docs/ReplaceRequest.md) - [ReplaceResult](docs/ReplaceResult.md) - [RepositoryUrl](docs/RepositoryUrl.md) + - [ResourceState](docs/ResourceState.md) + - [ResourceType](docs/ResourceType.md) + - [RunnerDTO](docs/RunnerDTO.md) + - [RunnerMetadata](docs/RunnerMetadata.md) - [Sample](docs/Sample.md) - [SearchFilesResponse](docs/SearchFilesResponse.md) - [ServerConfig](docs/ServerConfig.md) @@ -257,12 +279,24 @@ Class | Method | HTTP request | Description - [SessionExecuteRequest](docs/SessionExecuteRequest.md) - [SessionExecuteResponse](docs/SessionExecuteResponse.md) - [SetGitProviderConfig](docs/SetGitProviderConfig.md) - - [SetProjectState](docs/SetProjectState.md) - [SigningMethod](docs/SigningMethod.md) - [Status](docs/Status.md) + - [Target](docs/Target.md) + - [TargetConfig](docs/TargetConfig.md) + - [TargetConfigProperty](docs/TargetConfigProperty.md) + - [TargetDTO](docs/TargetDTO.md) + - [TargetMetadata](docs/TargetMetadata.md) + - [UpdateJobState](docs/UpdateJobState.md) + - [UpdateRunnerMetadataDTO](docs/UpdateRunnerMetadataDTO.md) + - [UpdateTargetMetadataDTO](docs/UpdateTargetMetadataDTO.md) + - [UpdateTargetProviderMetadataDTO](docs/UpdateTargetProviderMetadataDTO.md) + - [UpdateWorkspaceMetadataDTO](docs/UpdateWorkspaceMetadataDTO.md) + - [UpdateWorkspaceProviderMetadataDTO](docs/UpdateWorkspaceProviderMetadataDTO.md) - [Workspace](docs/Workspace.md) - [WorkspaceDTO](docs/WorkspaceDTO.md) - - [WorkspaceInfo](docs/WorkspaceInfo.md) + - [WorkspaceDirResponse](docs/WorkspaceDirResponse.md) + - [WorkspaceMetadata](docs/WorkspaceMetadata.md) + - [WorkspaceTemplate](docs/WorkspaceTemplate.md) ## Documentation For Authorization diff --git a/pkg/apiclient/api/openapi.yaml b/pkg/apiclient/api/openapi.yaml index d2e633c0f4..042bc63903 100644 --- a/pkg/apiclient/api/openapi.yaml +++ b/pkg/apiclient/api/openapi.yaml @@ -19,7 +19,7 @@ paths: application/json: schema: items: - $ref: '#/components/schemas/ApiKey' + $ref: '#/components/schemas/ApiKeyViewDTO' type: array description: OK summary: List API keys @@ -27,8 +27,8 @@ paths: - apiKey /apikey/{apiKeyName}: delete: - description: Revoke API key - operationId: RevokeApiKey + description: Delete API key + operationId: DeleteApiKey parameters: - description: API key name in: path @@ -40,12 +40,12 @@ paths: "200": content: {} description: OK - summary: Revoke API key + summary: Delete API key tags: - apiKey post: - description: Generate an API key - operationId: GenerateApiKey + description: Create an API key + operationId: CreateApiKey parameters: - description: API key name in: path @@ -60,7 +60,7 @@ paths: schema: type: string description: OK - summary: Generate an API key + summary: Create an API key tags: - apiKey /build: @@ -89,7 +89,7 @@ paths: application/json: schema: items: - $ref: '#/components/schemas/Build' + $ref: '#/components/schemas/BuildDTO' type: array description: OK summary: List builds @@ -139,6 +139,29 @@ paths: summary: Delete builds tags: - build + /build/successful/{repoUrl}: + get: + description: List successful builds for Git repository + operationId: ListSuccessfulBuilds + parameters: + - description: Repository URL + in: path + name: repoUrl + required: true + schema: + type: string + responses: + "200": + content: + application/json: + schema: + items: + $ref: '#/components/schemas/BuildDTO' + type: array + description: OK + summary: List successful builds for Git repository + tags: + - build /build/{buildId}: delete: description: Delete build @@ -163,8 +186,8 @@ paths: tags: - build get: - description: Get build data - operationId: GetBuild + description: Find build + operationId: FindBuild parameters: - description: Build ID in: path @@ -177,53 +200,25 @@ paths: content: '*/*': schema: - $ref: '#/components/schemas/Build' + $ref: '#/components/schemas/BuildDTO' description: OK - summary: Get build data + summary: Find build tags: - build - /container-registry: - get: - description: List container registries - operationId: ListContainerRegistries - responses: - "200": - content: - application/json: - schema: - items: - $ref: '#/components/schemas/ContainerRegistry' - type: array - description: OK - summary: List container registries - tags: - - container-registry /container-registry/{server}: - delete: - description: Remove a container registry credentials - operationId: RemoveContainerRegistry + get: + description: Find container registry + operationId: FindContainerRegistry parameters: - - description: Container Registry server name + - description: Container registry server in: path name: server required: true schema: type: string - responses: - "204": - content: {} - description: No Content - summary: Remove a container registry credentials - tags: - - container-registry - get: - description: Get container registry credentials - operationId: GetContainerRegistry - parameters: - - description: Container Registry server name - in: path - name: server - required: true + - description: Workspace ID or Name + in: query + name: workspaceId schema: type: string responses: @@ -233,34 +228,61 @@ paths: schema: $ref: '#/components/schemas/ContainerRegistry' description: OK - summary: Get container registry credentials + summary: Find container registry + tags: + - container registry + /env: + get: + description: List environment variables + operationId: ListEnvironmentVariables + responses: + "200": + content: + application/json: + schema: + items: + $ref: '#/components/schemas/EnvironmentVariable' + type: array + description: OK + summary: List environment variables tags: - - container-registry + - envVar put: - description: Set container registry credentials - operationId: SetContainerRegistry - parameters: - - description: Container Registry server name - in: path - name: server - required: true - schema: - type: string + description: Save environment variable + operationId: SaveEnvironmentVariable requestBody: content: - '*/*': + application/json: schema: - $ref: '#/components/schemas/ContainerRegistry' - description: Container Registry credentials to set + $ref: '#/components/schemas/EnvironmentVariable' + description: Environment Variable required: true responses: "201": content: {} description: Created - summary: Set container registry credentials + summary: Save environment variable + tags: + - envVar + x-codegen-request-body-name: environmentVariable + /env/{key}: + delete: + description: Delete environment variable + operationId: DeleteEnvironmentVariable + parameters: + - description: Environment Variable Key + in: path + name: key + required: true + schema: + type: string + responses: + "204": + content: {} + description: No Content + summary: Delete environment variable tags: - - container-registry - x-codegen-request-body-name: containerRegistry + - envVar /gitprovider: get: description: List Git providers @@ -278,8 +300,8 @@ paths: tags: - gitProvider put: - description: Set Git provider - operationId: SetGitProvider + description: Save Git provider + operationId: SaveGitProvider requestBody: content: '*/*': @@ -291,7 +313,7 @@ paths: "200": content: {} description: OK - summary: Set Git provider + summary: Save Git provider tags: - gitProvider x-codegen-request-body-name: gitProviderConfig @@ -364,8 +386,8 @@ paths: - gitProvider /gitprovider/id-for-url/{url}: get: - description: Get Git provider ID - operationId: GetGitProviderIdForUrl + description: Find Git provider ID + operationId: FindGitProviderIdForUrl parameters: - description: Url in: path @@ -380,13 +402,13 @@ paths: schema: type: string description: OK - summary: Get Git provider ID + summary: Find Git provider ID tags: - gitProvider /gitprovider/{gitProviderId}: delete: - description: Remove Git provider - operationId: RemoveGitProvider + description: Delete Git provider + operationId: DeleteGitProvider parameters: - description: Git provider in: path @@ -398,12 +420,12 @@ paths: "200": content: {} description: OK - summary: Remove Git provider + summary: Delete Git provider tags: - gitProvider get: - description: Get Git provider - operationId: GetGitProvider + description: Find Git provider + operationId: FindGitProvider parameters: - description: ID in: path @@ -418,7 +440,7 @@ paths: schema: $ref: '#/components/schemas/GitProvider' description: OK - summary: Get Git provider + summary: Find Git provider tags: - gitProvider /gitprovider/{gitProviderId}/namespaces: @@ -618,91 +640,96 @@ paths: type: object description: OK summary: Health check - /profile: - delete: - description: Delete profile data - operationId: DeleteProfileData - responses: - "204": - content: {} - description: No Content - summary: Delete profile data - tags: - - profile + /job: get: - description: Get profile data - operationId: GetProfileData + description: List jobs + operationId: ListJobs + parameters: + - description: Job States + explode: true + in: query + name: states + schema: + items: + type: string + type: array + style: form + - description: Job Actions + explode: true + in: query + name: actions + schema: + items: + type: string + type: array + style: form + - description: Resource ID + in: query + name: resourceId + schema: + type: string + - description: Resource Type + in: query + name: resourceType + schema: + type: string responses: "200": content: - '*/*': + application/json: schema: - $ref: '#/components/schemas/ProfileData' + items: + $ref: '#/components/schemas/Job' + type: array description: OK - summary: Get profile data - tags: - - profile - put: - description: Set profile data - operationId: SetProfileData - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/ProfileData' - description: Profile data - required: true - responses: - "201": - content: {} - description: Created - summary: Set profile data + summary: List jobs tags: - - profile - x-codegen-request-body-name: profileData - /project-config: + - job + /runner: get: - description: List project configs - operationId: ListProjectConfigs + description: List runners + operationId: ListRunners responses: "200": content: application/json: schema: items: - $ref: '#/components/schemas/ProjectConfig' + $ref: '#/components/schemas/RunnerDTO' type: array description: OK - summary: List project configs + summary: List runners tags: - - project-config - put: - description: Set project config data - operationId: SetProjectConfig + - runner + post: + description: Create a runner + operationId: CreateRunner requestBody: content: - application/json: + '*/*': schema: - $ref: '#/components/schemas/CreateProjectConfigDTO' - description: Project config + $ref: '#/components/schemas/CreateRunnerDTO' + description: Runner required: true responses: - "201": - content: {} - description: Created - summary: Set project config data + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/CreateRunnerResultDTO' + description: OK + summary: Create a runner tags: - - project-config - x-codegen-request-body-name: projectConfig - /project-config/default/{gitUrl}: + - runner + x-codegen-request-body-name: runner + /runner/provider: get: - description: Get project configs by git url - operationId: GetDefaultProjectConfig + description: List providers + operationId: ListProviders parameters: - - description: Git URL - in: path - name: gitUrl - required: true + - description: Runner ID + in: query + name: runnerId schema: type: string responses: @@ -710,285 +737,251 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/ProjectConfig' + items: + $ref: '#/components/schemas/ProviderInfo' + type: array description: OK - summary: Get project configs by git url + summary: List providers tags: - - project-config - /project-config/prebuild: + - provider + /runner/provider/for-install: get: - description: List prebuilds - operationId: ListPrebuilds + description: List providers available for installation + operationId: ListProvidersForInstall responses: "200": content: - '*/*': + application/json: schema: items: - $ref: '#/components/schemas/PrebuildDTO' + $ref: '#/components/schemas/ProviderDTO' type: array description: OK - summary: List prebuilds - tags: - - prebuild - /project-config/prebuild/process-git-event: - post: - description: ProcessGitEvent - operationId: ProcessGitEvent - requestBody: - content: - '*/*': - schema: - type: object - description: Webhook event - required: true - responses: - "200": - content: {} - description: OK - summary: ProcessGitEvent + summary: List providers available for installation tags: - - prebuild - x-codegen-request-body-name: workspace - /project-config/{configName}: + - provider + /runner/{runnerId}: delete: - description: Delete project config data - operationId: DeleteProjectConfig + description: Delete runner + operationId: DeleteRunner parameters: - - description: Config name + - description: Runner ID in: path - name: configName + name: runnerId required: true schema: type: string - - description: Force - in: query - name: force - schema: - type: boolean responses: - "204": + "200": content: {} - description: No Content - summary: Delete project config data + description: OK + summary: Delete runner tags: - - project-config + - runner get: - description: Get project config data - operationId: GetProjectConfig + description: Find a runner + operationId: FindRunner parameters: - - description: Config name + - description: Runner ID in: path - name: configName + name: runnerId required: true schema: type: string responses: "200": content: - '*/*': + application/json: schema: - $ref: '#/components/schemas/ProjectConfig' + $ref: '#/components/schemas/RunnerDTO' description: OK - summary: Get project config data + summary: Find a runner tags: - - project-config - /project-config/{configName}/prebuild: + - runner + /runner/{runnerId}/jobs: get: - description: List prebuilds for project config - operationId: ListPrebuildsForProjectConfig + description: List runner jobs + operationId: ListRunnerJobs parameters: - - description: Config name + - description: Runner ID in: path - name: configName + name: runnerId required: true schema: type: string responses: "200": content: - '*/*': + application/json: schema: items: - $ref: '#/components/schemas/PrebuildDTO' + $ref: '#/components/schemas/Job' type: array description: OK - summary: List prebuilds for project config + summary: List runner jobs tags: - - prebuild - put: - description: Set prebuild - operationId: SetPrebuild + - runner + /runner/{runnerId}/jobs/{jobId}/state: + post: + description: Update job state + operationId: UpdateJobState parameters: - - description: Config name + - description: Runner ID in: path - name: configName + name: runnerId required: true schema: type: string - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/CreatePrebuildDTO' - description: Prebuild - required: true - responses: - "201": - content: - '*/*': - schema: - type: string - description: Created - summary: Set prebuild - tags: - - prebuild - x-codegen-request-body-name: prebuild - /project-config/{configName}/prebuild/{prebuildId}: - delete: - description: Delete prebuild - operationId: DeletePrebuild - parameters: - - description: Project config name + - description: Job ID in: path - name: configName + name: jobId required: true schema: type: string - - description: Prebuild ID - in: path - name: prebuildId + requestBody: + content: + '*/*': + schema: + $ref: '#/components/schemas/UpdateJobState' + description: Update job state required: true - schema: - type: string - - description: Force - in: query - name: force - schema: - type: boolean responses: - "204": + "200": content: {} - description: No Content - summary: Delete prebuild + description: OK + summary: Update job state tags: - - prebuild - get: - description: Get prebuild - operationId: GetPrebuild + - runner + x-codegen-request-body-name: updateJobState + /runner/{runnerId}/metadata: + post: + description: Update runner metadata + operationId: UpdateRunnerMetadata parameters: - - description: Project config name + - description: Runner ID in: path - name: configName + name: runnerId required: true schema: type: string - - description: Prebuild ID - in: path - name: prebuildId + requestBody: + content: + '*/*': + schema: + $ref: '#/components/schemas/UpdateRunnerMetadataDTO' + description: Runner Metadata required: true - schema: - type: string responses: "200": - content: - '*/*': - schema: - $ref: '#/components/schemas/PrebuildDTO' + content: {} description: OK - summary: Get prebuild + summary: Update runner metadata tags: - - prebuild - /project-config/{configName}/set-default: - patch: - description: Set project config to default - operationId: SetDefaultProjectConfig + - runner + x-codegen-request-body-name: runnerMetadata + /runner/{runnerId}/provider: + get: + description: Get runner providers + operationId: GetRunnerProviders parameters: - - description: Config name + - description: Runner ID in: path - name: configName + name: runnerId required: true schema: type: string - responses: - "200": - content: {} - description: OK - summary: Set project config to default - tags: - - project-config - /provider: - get: - description: List providers - operationId: ListProviders responses: "200": content: application/json: schema: items: - $ref: '#/components/schemas/Provider' + $ref: '#/components/schemas/ProviderInfo' type: array description: OK - summary: List providers + summary: Get runner providers tags: - provider - /provider/install: + /runner/{runnerId}/provider/{providerName}/install: post: - description: Install a provider + description: Install provider operationId: InstallProvider - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/InstallProviderRequest' - description: Provider to install - required: true - responses: - "200": - content: {} - description: OK - summary: Install a provider - tags: - - provider - x-codegen-request-body-name: provider - /provider/{provider}/target-manifest: - get: - description: Get provider target manifest - operationId: GetTargetManifest parameters: - - description: Provider name + - description: Runner ID in: path - name: provider + name: runnerId required: true schema: type: string + - description: Provider name + in: path + name: providerName + required: true + schema: + type: string + - description: Provider version - defaults to 'latest' + in: query + name: providerVersion + schema: + type: string responses: "200": - content: - '*/*': - schema: - $ref: '#/components/schemas/ProviderTargetManifest' + content: {} description: OK - summary: Get provider target manifest + summary: Install provider tags: - provider - /provider/{provider}/uninstall: + /runner/{runnerId}/provider/{providerName}/uninstall: post: - description: Uninstall a provider + description: Uninstall provider operationId: UninstallProvider parameters: - - description: Provider to uninstall + - description: Runner ID + in: path + name: runnerId + required: true + schema: + type: string + - description: Provider name + in: path + name: providerName + required: true + schema: + type: string + responses: + "200": + content: {} + description: OK + summary: Uninstall provider + tags: + - provider + /runner/{runnerId}/provider/{providerName}/update: + post: + description: Update provider + operationId: UpdateProvider + parameters: + - description: Runner ID + in: path + name: runnerId + required: true + schema: + type: string + - description: Provider name in: path - name: provider + name: providerName required: true schema: type: string + - description: Provider version - defaults to 'latest' + in: query + name: providerVersion + schema: + type: string responses: "200": content: {} description: OK - summary: Uninstall a provider + summary: Update provider tags: - provider /sample: @@ -1021,9 +1014,9 @@ paths: summary: Get the server configuration tags: - server - post: - description: Set the server configuration - operationId: SetConfig + put: + description: Save the server configuration + operationId: SaveConfig requestBody: content: application/json: @@ -1038,13 +1031,13 @@ paths: schema: $ref: '#/components/schemas/ServerConfig' description: OK - summary: Set the server configuration + summary: Save the server configuration tags: - server x-codegen-request-body-name: config /server/logs: get: - description: List server log files + description: Get server log files operationId: GetServerLogFiles responses: "200": @@ -1055,13 +1048,13 @@ paths: type: string type: array description: OK - summary: List server log files + summary: Get server log files tags: - server /server/network-key: post: - description: Generate a new authentication key - operationId: GenerateNetworkKey + description: Create a new authentication key + operationId: CreateNetworkKey responses: "200": content: @@ -1069,87 +1062,60 @@ paths: schema: $ref: '#/components/schemas/NetworkKey' description: OK - summary: Generate a new authentication key + summary: Create a new authentication key tags: - server /target: get: description: List targets operationId: ListTargets + parameters: + - description: Show target config options + in: query + name: showOptions + schema: + type: boolean responses: "200": content: application/json: schema: items: - $ref: '#/components/schemas/ProviderTarget' + $ref: '#/components/schemas/TargetDTO' type: array description: OK summary: List targets tags: - target - put: - description: Set a target - operationId: SetTarget + post: + description: Create a target + operationId: CreateTarget requestBody: content: '*/*': schema: - $ref: '#/components/schemas/CreateProviderTargetDTO' - description: Target to set - required: true - responses: - "201": - content: {} - description: Created - summary: Set a target - tags: - - target - x-codegen-request-body-name: target - /target/{target}: - delete: - description: Remove a target - operationId: RemoveTarget - parameters: - - description: Target name - in: path - name: target - required: true - schema: - type: string - responses: - "204": - content: {} - description: No Content - summary: Remove a target - tags: - - target - /target/{target}/set-default: - patch: - description: Set target to default - operationId: SetDefaultTarget - parameters: - - description: Target name - in: path - name: target + $ref: '#/components/schemas/CreateTargetDTO' + description: Create target required: true - schema: - type: string responses: "200": - content: {} + content: + application/json: + schema: + $ref: '#/components/schemas/Target' description: OK - summary: Set target to default + summary: Create a target tags: - target - /workspace: + x-codegen-request-body-name: target + /target-config: get: - description: List workspaces - operationId: ListWorkspaces + description: List target configs + operationId: ListTargetConfigs parameters: - - description: Verbose + - description: Show target config options in: query - name: verbose + name: showOptions schema: type: boolean responses: @@ -1158,41 +1124,65 @@ paths: application/json: schema: items: - $ref: '#/components/schemas/WorkspaceDTO' + $ref: '#/components/schemas/TargetConfig' type: array description: OK - summary: List workspaces + summary: List target configs tags: - - workspace + - target-config post: - description: Create a workspace - operationId: CreateWorkspace + description: Create a target config + operationId: CreateTargetConfig + parameters: + - description: Show target config options + in: query + name: showOptions + schema: + type: boolean requestBody: content: '*/*': schema: - $ref: '#/components/schemas/CreateWorkspaceDTO' - description: Create workspace + $ref: '#/components/schemas/CreateTargetConfigDTO' + description: Target config to create required: true responses: "200": content: - application/json: + '*/*': schema: - $ref: '#/components/schemas/Workspace' + $ref: '#/components/schemas/TargetConfig' description: OK - summary: Create a workspace + summary: Create a target config tags: - - workspace - x-codegen-request-body-name: workspace - /workspace/{workspaceId}: + - target-config + x-codegen-request-body-name: targetConfig + /target-config/{configId}: delete: - description: Remove workspace - operationId: RemoveWorkspace + description: Delete a target config + operationId: DeleteTargetConfig parameters: - - description: Workspace ID + - description: Target Config Id in: path - name: workspaceId + name: configId + required: true + schema: + type: string + responses: + "204": + content: {} + description: No Content + summary: Delete a target config + tags: + - target-config + /target/{targetId}: + delete: + description: Delete target + operationId: DeleteTarget + parameters: + - description: Target ID + in: path + name: targetId required: true schema: type: string @@ -1205,22 +1195,22 @@ paths: "200": content: {} description: OK - summary: Remove workspace + summary: Delete target tags: - - workspace + - target get: - description: Get workspace info - operationId: GetWorkspace + description: Find target + operationId: FindTarget parameters: - - description: Workspace ID or Name + - description: Target ID or Name in: path - name: workspaceId + name: targetId required: true schema: type: string - - description: Verbose + - description: Show target config options in: query - name: verbose + name: showOptions schema: type: boolean responses: @@ -1228,19 +1218,19 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/WorkspaceDTO' + $ref: '#/components/schemas/TargetDTO' description: OK - summary: Get workspace info + summary: Find target tags: - - workspace - /workspace/{workspaceId}/start: + - target + /target/{targetId}/handle-successful-creation: post: - description: Start workspace - operationId: StartWorkspace + description: Handles successful creation of the target + operationId: HandleSuccessfulCreation parameters: - - description: Workspace ID or Name + - description: Target ID or name in: path - name: workspaceId + name: targetId required: true schema: type: string @@ -1248,97 +1238,105 @@ paths: "200": content: {} description: OK - summary: Start workspace + summary: Handles successful creation of the target tags: - - workspace - /workspace/{workspaceId}/stop: + - target + /target/{targetId}/metadata: post: - description: Stop workspace - operationId: StopWorkspace + description: Update target metadata + operationId: UpdateTargetMetadata parameters: - - description: Workspace ID or Name + - description: Target ID in: path - name: workspaceId + name: targetId required: true schema: type: string + requestBody: + content: + '*/*': + schema: + $ref: '#/components/schemas/UpdateTargetMetadataDTO' + description: Target Metadata + required: true responses: "200": content: {} description: OK - summary: Stop workspace + summary: Update target metadata tags: - - workspace - /workspace/{workspaceId}/{projectId}/start: + - target + x-codegen-request-body-name: targetMetadata + /target/{targetId}/provider-metadata: post: - description: Start project - operationId: StartProject + description: Update target provider metadata + operationId: UpdateTargetProviderMetadata parameters: - - description: Workspace ID or Name + - description: Target ID in: path - name: workspaceId + name: targetId required: true schema: type: string - - description: Project ID - in: path - name: projectId + requestBody: + content: + '*/*': + schema: + $ref: '#/components/schemas/UpdateTargetProviderMetadataDTO' + description: Provider metadata required: true - schema: - type: string responses: "200": content: {} description: OK - summary: Start project + summary: Update target provider metadata tags: - - workspace - /workspace/{workspaceId}/{projectId}/state: + - target + x-codegen-request-body-name: metadata + /target/{targetId}/restart: post: - description: Set project state - operationId: SetProjectState + description: Restart target + operationId: RestartTarget parameters: - - description: Workspace ID or Name + - description: Target ID or Name in: path - name: workspaceId + name: targetId required: true schema: type: string - - description: Project ID + responses: + "200": + content: {} + description: OK + summary: Restart target + tags: + - target + /target/{targetId}/set-default: + patch: + description: Set target to be used by default + operationId: SetDefaultTarget + parameters: + - description: Target ID or name in: path - name: projectId + name: targetId required: true schema: type: string - requestBody: - content: - '*/*': - schema: - $ref: '#/components/schemas/SetProjectState' - description: Set State - required: true responses: "200": content: {} description: OK - summary: Set project state + summary: Set target to be used by default tags: - - workspace - x-codegen-request-body-name: setState - /workspace/{workspaceId}/{projectId}/stop: + - target + /target/{targetId}/start: post: - description: Stop project - operationId: StopProject + description: Start target + operationId: StartTarget parameters: - - description: Workspace ID or Name - in: path - name: workspaceId - required: true - schema: - type: string - - description: Project ID + - description: Target ID or Name in: path - name: projectId + name: targetId required: true schema: type: string @@ -1346,58 +1344,56 @@ paths: "200": content: {} description: OK - summary: Stop project + summary: Start target tags: - - workspace - /workspace/{workspaceId}/{projectId}/toolbox/files: - delete: - description: Delete file inside workspace project - operationId: FsDeleteFile + - target + /target/{targetId}/state: + get: + description: Get target state + operationId: GetTargetState parameters: - - description: Workspace ID or Name + - description: Target ID or Name in: path - name: workspaceId + name: targetId required: true schema: type: string - - description: Project ID + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/ResourceState' + description: OK + summary: Get target state + tags: + - target + /target/{targetId}/stop: + post: + description: Stop target + operationId: StopTarget + parameters: + - description: Target ID or Name in: path - name: projectId - required: true - schema: - type: string - - description: Path - in: query - name: path + name: targetId required: true schema: type: string responses: - "204": + "200": content: {} - description: No Content - summary: Delete file + description: OK + summary: Stop target tags: - - workspace toolbox + - target + /workspace: get: - description: List files inside workspace project - operationId: FsListFiles + description: List workspaces + operationId: ListWorkspaces parameters: - - description: Workspace ID or Name - in: path - name: workspaceId - required: true - schema: - type: string - - description: Project ID - in: path - name: projectId - required: true - schema: - type: string - - description: Path + - description: JSON encoded labels in: query - name: path + name: labels schema: type: string responses: @@ -1406,196 +1402,316 @@ paths: application/json: schema: items: - $ref: '#/components/schemas/FileInfo' + $ref: '#/components/schemas/WorkspaceDTO' type: array description: OK - summary: List files + summary: List workspaces tags: - - workspace toolbox - /workspace/{workspaceId}/{projectId}/toolbox/files/download: - get: - description: Download file from workspace project - operationId: FsDownloadFile - parameters: - - description: Workspace ID or Name - in: path - name: workspaceId - required: true - schema: - type: string - - description: Project ID - in: path - name: projectId - required: true - schema: - type: string - - description: Path - in: query - name: path + - workspace + post: + description: Create a workspace + operationId: CreateWorkspace + requestBody: + content: + '*/*': + schema: + $ref: '#/components/schemas/CreateWorkspaceDTO' + description: Create workspace required: true - schema: - type: string responses: "200": content: application/json: schema: - format: binary - type: string - description: response contains the file - summary: Download file - tags: - - workspace toolbox - /workspace/{workspaceId}/{projectId}/toolbox/files/find: + $ref: '#/components/schemas/WorkspaceDTO' + description: OK + summary: Create a workspace + tags: + - workspace + x-codegen-request-body-name: workspace + /workspace-template: get: - description: Search for text/pattern inside workspace project files - operationId: FsFindInFiles + description: List workspace templates + operationId: ListWorkspaceTemplates + responses: + "200": + content: + application/json: + schema: + items: + $ref: '#/components/schemas/WorkspaceTemplate' + type: array + description: OK + summary: List workspace templates + tags: + - workspace-template + put: + description: Set workspace template data + operationId: SaveWorkspaceTemplate + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/CreateWorkspaceTemplateDTO' + description: Workspace template + required: true + responses: + "201": + content: {} + description: Created + summary: Set workspace template data + tags: + - workspace-template + x-codegen-request-body-name: workspaceTemplate + /workspace-template/default/{gitUrl}: + get: + description: Get default workspace templates by git url + operationId: GetDefaultWorkspaceTemplate parameters: - - description: Workspace ID or Name + - description: Git URL in: path - name: workspaceId + name: gitUrl required: true schema: type: string - - description: Project ID + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/WorkspaceTemplate' + description: OK + summary: Get default workspace templates by git url + tags: + - workspace-template + /workspace-template/prebuild: + get: + description: List prebuilds + operationId: ListPrebuilds + responses: + "200": + content: + '*/*': + schema: + items: + $ref: '#/components/schemas/PrebuildDTO' + type: array + description: OK + summary: List prebuilds + tags: + - prebuild + /workspace-template/prebuild/process-git-event: + post: + description: ProcessGitEvent + operationId: ProcessGitEvent + requestBody: + content: + '*/*': + schema: + type: object + description: Webhook event + required: true + responses: + "200": + content: {} + description: OK + summary: ProcessGitEvent + tags: + - prebuild + x-codegen-request-body-name: body + /workspace-template/{templateName}: + delete: + description: Delete workspace template data + operationId: DeleteWorkspaceTemplate + parameters: + - description: Template name in: path - name: projectId + name: templateName required: true schema: type: string - - description: Path + - description: Force in: query - name: path + name: force + schema: + type: boolean + responses: + "204": + content: {} + description: No Content + summary: Delete workspace template data + tags: + - workspace-template + get: + description: Find a workspace template + operationId: FindWorkspaceTemplate + parameters: + - description: Template name + in: path + name: templateName required: true schema: type: string - - description: Pattern - in: query - name: pattern + responses: + "200": + content: + '*/*': + schema: + $ref: '#/components/schemas/WorkspaceTemplate' + description: OK + summary: Find a workspace template + tags: + - workspace-template + /workspace-template/{templateName}/prebuild: + get: + description: List prebuilds for workspace template + operationId: ListPrebuildsForWorkspaceTemplate + parameters: + - description: Template name + in: path + name: templateName required: true schema: type: string responses: "200": content: - application/json: + '*/*': schema: items: - $ref: '#/components/schemas/Match' + $ref: '#/components/schemas/PrebuildDTO' type: array description: OK - summary: Search for text/pattern in files + summary: List prebuilds for workspace template tags: - - workspace toolbox - /workspace/{workspaceId}/{projectId}/toolbox/files/folder: - post: - description: Create folder inside workspace project - operationId: FsCreateFolder + - prebuild + put: + description: Save prebuild + operationId: SavePrebuild parameters: - - description: Workspace ID or Name + - description: Template name in: path - name: workspaceId + name: templateName required: true schema: type: string - - description: Project ID + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/CreatePrebuildDTO' + description: Prebuild + required: true + responses: + "201": + content: + '*/*': + schema: + type: string + description: Created + summary: Save prebuild + tags: + - prebuild + x-codegen-request-body-name: prebuild + /workspace-template/{templateName}/prebuild/{prebuildId}: + delete: + description: Delete prebuild + operationId: DeletePrebuild + parameters: + - description: Workspace template name in: path - name: projectId + name: templateName required: true schema: type: string - - description: Path - in: query - name: path + - description: Prebuild ID + in: path + name: prebuildId required: true schema: type: string - - description: Mode + - description: Force in: query - name: mode - required: true + name: force schema: - type: string + type: boolean responses: - "201": + "204": content: {} - description: Created - summary: Create folder + description: No Content + summary: Delete prebuild tags: - - workspace toolbox - /workspace/{workspaceId}/{projectId}/toolbox/files/info: + - prebuild get: - description: Get file info inside workspace project - operationId: FsGetFileDetails + description: Find prebuild + operationId: FindPrebuild parameters: - - description: Workspace ID or Name + - description: Workspace template name in: path - name: workspaceId + name: templateName required: true schema: type: string - - description: Project ID + - description: Prebuild ID in: path - name: projectId - required: true - schema: - type: string - - description: Path - in: query - name: path + name: prebuildId required: true schema: type: string responses: "200": content: - application/json: + '*/*': schema: - $ref: '#/components/schemas/FileInfo' + $ref: '#/components/schemas/PrebuildDTO' description: OK - summary: Get file info + summary: Find prebuild tags: - - workspace toolbox - /workspace/{workspaceId}/{projectId}/toolbox/files/move: - post: - description: Create folder inside workspace project - operationId: FsMoveFile + - prebuild + /workspace-template/{templateName}/set-default: + patch: + description: Set workspace template to default + operationId: SetDefaultWorkspaceTemplate parameters: - - description: Workspace ID or Name + - description: Template name in: path - name: workspaceId + name: templateName required: true schema: type: string - - description: Project ID + responses: + "200": + content: {} + description: OK + summary: Set workspace template to default + tags: + - workspace-template + /workspace/{workspaceId}: + delete: + description: Delete workspace + operationId: DeleteWorkspace + parameters: + - description: Workspace ID in: path - name: projectId - required: true - schema: - type: string - - description: Source path - in: query - name: source + name: workspaceId required: true schema: type: string - - description: Destination path + - description: Force in: query - name: destination - required: true + name: force schema: - type: string + type: boolean responses: "200": content: {} description: OK - summary: Create folder + summary: Delete workspace tags: - - workspace toolbox - /workspace/{workspaceId}/{projectId}/toolbox/files/permissions: - post: - description: Set file owner/group/permissions inside workspace project - operationId: FsSetFilePermissions + - workspace + get: + description: Find workspace + operationId: FindWorkspace parameters: - description: Workspace ID or Name in: path @@ -1603,44 +1719,20 @@ paths: required: true schema: type: string - - description: Project ID - in: path - name: projectId - required: true - schema: - type: string - - description: Path - in: query - name: path - required: true - schema: - type: string - - description: Owner - in: query - name: owner - schema: - type: string - - description: Group - in: query - name: group - schema: - type: string - - description: Mode - in: query - name: mode - schema: - type: string responses: "200": - content: {} + content: + application/json: + schema: + $ref: '#/components/schemas/WorkspaceDTO' description: OK - summary: Set file owner/group/permissions + summary: Find workspace tags: - - workspace toolbox - /workspace/{workspaceId}/{projectId}/toolbox/files/replace: + - workspace + /workspace/{workspaceId}/labels: post: - description: Repleace text/pattern in mutilple files inside workspace project - operationId: FsReplaceInFiles + description: Update workspace labels + operationId: UpdateWorkspaceLabels parameters: - description: Workspace ID or Name in: path @@ -1648,111 +1740,82 @@ paths: required: true schema: type: string - - description: Project ID - in: path - name: projectId - required: true - schema: - type: string requestBody: content: '*/*': schema: - $ref: '#/components/schemas/ReplaceRequest' - description: ReplaceParams + additionalProperties: + type: string + type: object + description: Labels required: true responses: "200": content: - application/json: + '*/*': schema: - items: - $ref: '#/components/schemas/ReplaceResult' - type: array + $ref: '#/components/schemas/WorkspaceDTO' description: OK - summary: Repleace text/pattern in files + summary: Update workspace labels tags: - - workspace toolbox - x-codegen-request-body-name: replace - /workspace/{workspaceId}/{projectId}/toolbox/files/search: - get: - description: Search for files inside workspace project - operationId: FsSearchFiles + - workspace + x-codegen-request-body-name: labels + /workspace/{workspaceId}/metadata: + post: + description: Update workspace metadata + operationId: UpdateWorkspaceMetadata parameters: - - description: Workspace ID or Name + - description: Workspace ID in: path name: workspaceId required: true schema: type: string - - description: Project ID - in: path - name: projectId - required: true - schema: - type: string - - description: Path - in: query - name: path - required: true - schema: - type: string - - description: Pattern - in: query - name: pattern + requestBody: + content: + '*/*': + schema: + $ref: '#/components/schemas/UpdateWorkspaceMetadataDTO' + description: Workspace Metadata required: true - schema: - type: string responses: "200": - content: - application/json: - schema: - $ref: '#/components/schemas/SearchFilesResponse' + content: {} description: OK - summary: Search for files + summary: Update workspace metadata tags: - - workspace toolbox - /workspace/{workspaceId}/{projectId}/toolbox/files/upload: + - workspace + x-codegen-request-body-name: workspaceMetadata + /workspace/{workspaceId}/provider-metadata: post: - description: Upload file inside workspace project - operationId: FsUploadFile + description: Update workspace provider metadata + operationId: UpdateWorkspaceProviderMetadata parameters: - - description: Workspace ID or Name + - description: Workspace ID in: path name: workspaceId required: true schema: type: string - - description: Project ID - in: path - name: projectId - required: true - schema: - type: string - - description: Path - in: query - name: path - required: true - schema: - type: string requestBody: content: - multipart/form-data: + '*/*': schema: - $ref: '#/components/schemas/FsUploadFile_request' + $ref: '#/components/schemas/UpdateWorkspaceProviderMetadataDTO' + description: Provider metadata required: true responses: "200": content: {} description: OK - summary: Upload file + summary: Update workspace provider metadata tags: - - workspace toolbox - /workspace/{workspaceId}/{projectId}/toolbox/git/add: + - workspace + x-codegen-request-body-name: metadata + /workspace/{workspaceId}/restart: post: - description: Add files to git commit - operationId: GitAddFiles + description: Restart workspace + operationId: RestartWorkspace parameters: - description: Workspace ID or Name in: path @@ -1760,31 +1823,35 @@ paths: required: true schema: type: string - - description: Project ID + responses: + "200": + content: {} + description: OK + summary: Restart workspace + tags: + - workspace + /workspace/{workspaceId}/start: + post: + description: Start workspace + operationId: StartWorkspace + parameters: + - description: Workspace ID or Name in: path - name: projectId + name: workspaceId required: true schema: type: string - requestBody: - content: - '*/*': - schema: - $ref: '#/components/schemas/GitAddRequest' - description: GitAddRequest - required: true responses: "200": content: {} description: OK - summary: Add files + summary: Start workspace tags: - - workspace toolbox - x-codegen-request-body-name: params - /workspace/{workspaceId}/{projectId}/toolbox/git/branches: + - workspace + /workspace/{workspaceId}/state: get: - description: Get branch list from git repository inside workspace project - operationId: GitBranchList + description: Get workspace state + operationId: GetWorkspaceState parameters: - description: Workspace ID or Name in: path @@ -1792,31 +1859,20 @@ paths: required: true schema: type: string - - description: Project ID - in: path - name: projectId - required: true - schema: - type: string - - description: Path to git repository - in: query - name: path - required: true - schema: - type: string responses: "200": content: application/json: schema: - $ref: '#/components/schemas/ListBranchResponse' + $ref: '#/components/schemas/ResourceState' description: OK - summary: Get branch list + summary: Get workspace state tags: - - workspace toolbox + - workspace + /workspace/{workspaceId}/stop: post: - description: Create branch on git repository inside workspace project - operationId: GitCreateBranch + description: Stop workspace + operationId: StopWorkspace parameters: - description: Workspace ID or Name in: path @@ -1824,31 +1880,17 @@ paths: required: true schema: type: string - - description: Project ID - in: path - name: projectId - required: true - schema: - type: string - requestBody: - content: - '*/*': - schema: - $ref: '#/components/schemas/GitBranchRequest' - description: GitBranchRequest - required: true responses: - "201": + "200": content: {} - description: Created - summary: Create branch + description: OK + summary: Stop workspace tags: - - workspace toolbox - x-codegen-request-body-name: params - /workspace/{workspaceId}/{projectId}/toolbox/git/clone: - post: - description: Clone git repository inside workspace project - operationId: GitCloneRepository + - workspace + /workspace/{workspaceId}/toolbox/files: + delete: + description: Delete file inside a workspace + operationId: FsDeleteFile parameters: - description: Workspace ID or Name in: path @@ -1856,31 +1898,22 @@ paths: required: true schema: type: string - - description: Project ID - in: path - name: projectId + - description: Path + in: query + name: path required: true schema: type: string - requestBody: - content: - '*/*': - schema: - $ref: '#/components/schemas/GitCloneRequest' - description: GitCloneRequest - required: true responses: - "200": + "204": content: {} - description: OK - summary: Clone git repository + description: No Content + summary: Delete file tags: - workspace toolbox - x-codegen-request-body-name: params - /workspace/{workspaceId}/{projectId}/toolbox/git/commit: - post: - description: Commit changes to git repository inside workspace project - operationId: GitCommitChanges + get: + description: List files inside a workspace + operationId: FsListFiles parameters: - description: Workspace ID or Name in: path @@ -1888,34 +1921,27 @@ paths: required: true schema: type: string - - description: Project ID - in: path - name: projectId - required: true + - description: Path + in: query + name: path schema: type: string - requestBody: - content: - '*/*': - schema: - $ref: '#/components/schemas/GitCommitRequest' - description: GitCommitRequest - required: true responses: "200": content: application/json: schema: - $ref: '#/components/schemas/GitCommitResponse' + items: + $ref: '#/components/schemas/FileInfo' + type: array description: OK - summary: Commit changes + summary: List files tags: - workspace toolbox - x-codegen-request-body-name: params - /workspace/{workspaceId}/{projectId}/toolbox/git/history: + /workspace/{workspaceId}/toolbox/files/download: get: - description: Get commit history from git repository inside workspace project - operationId: GitCommitHistory + description: Download file from a workspace + operationId: FsDownloadFile parameters: - description: Workspace ID or Name in: path @@ -1923,13 +1949,7 @@ paths: required: true schema: type: string - - description: Project ID - in: path - name: projectId - required: true - schema: - type: string - - description: Path to git repository + - description: Path in: query name: path required: true @@ -1940,17 +1960,16 @@ paths: content: application/json: schema: - items: - $ref: '#/components/schemas/GitCommitInfo' - type: array - description: OK - summary: Get commit history + format: binary + type: string + description: response contains the file + summary: Download file tags: - workspace toolbox - /workspace/{workspaceId}/{projectId}/toolbox/git/pull: - post: - description: Pull changes from remote to git repository inside workspace project - operationId: GitPullChanges + /workspace/{workspaceId}/toolbox/files/find: + get: + description: Search for text/pattern inside a workspace files + operationId: FsFindInFiles parameters: - description: Workspace ID or Name in: path @@ -1958,31 +1977,34 @@ paths: required: true schema: type: string - - description: Project ID - in: path - name: projectId + - description: Path + in: query + name: path required: true schema: type: string - requestBody: - content: - '*/*': - schema: - $ref: '#/components/schemas/GitRepoRequest' - description: Git pull request + - description: Pattern + in: query + name: pattern required: true + schema: + type: string responses: "200": - content: {} + content: + application/json: + schema: + items: + $ref: '#/components/schemas/Match' + type: array description: OK - summary: Pull changes + summary: Search for text/pattern in files tags: - workspace toolbox - x-codegen-request-body-name: params - /workspace/{workspaceId}/{projectId}/toolbox/git/push: + /workspace/{workspaceId}/toolbox/files/folder: post: - description: Push changes to remote from git repository inside workspace project - operationId: GitPushChanges + description: Create folder inside a workspace + operationId: FsCreateFolder parameters: - description: Workspace ID or Name in: path @@ -1990,31 +2012,29 @@ paths: required: true schema: type: string - - description: Project ID - in: path - name: projectId + - description: Path + in: query + name: path required: true schema: type: string - requestBody: - content: - '*/*': - schema: - $ref: '#/components/schemas/GitRepoRequest' - description: Git push request + - description: Mode + in: query + name: mode required: true + schema: + type: string responses: - "200": + "201": content: {} - description: OK - summary: Push changes + description: Created + summary: Create folder tags: - workspace toolbox - x-codegen-request-body-name: params - /workspace/{workspaceId}/{projectId}/toolbox/git/status: + /workspace/{workspaceId}/toolbox/files/info: get: - description: Get status from git repository inside workspace project - operationId: GitGitStatus + description: Get file info inside a workspace + operationId: FsGetFileDetails parameters: - description: Workspace ID or Name in: path @@ -2022,13 +2042,7 @@ paths: required: true schema: type: string - - description: Project ID - in: path - name: projectId - required: true - schema: - type: string - - description: Path to git repository + - description: Path in: query name: path required: true @@ -2039,16 +2053,15 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/GitStatus' + $ref: '#/components/schemas/FileInfo' description: OK - summary: Get git status + summary: Get file info tags: - workspace toolbox - /workspace/{workspaceId}/{projectId}/toolbox/lsp/completions: + /workspace/{workspaceId}/toolbox/files/move: post: - description: The Completion request is sent from the client to the server to - compute completion items at a given cursor position. - operationId: LspCompletions + description: Create folder inside a workspace + operationId: FsMoveFile parameters: - description: Workspace ID or Name in: path @@ -2056,35 +2069,29 @@ paths: required: true schema: type: string - - description: Project ID - in: path - name: projectId + - description: Source path + in: query + name: source required: true schema: type: string - requestBody: - content: - '*/*': - schema: - $ref: '#/components/schemas/LspCompletionParams' - description: LspCompletionParams + - description: Destination path + in: query + name: destination required: true + schema: + type: string responses: "200": - content: - application/json: - schema: - $ref: '#/components/schemas/CompletionList' + content: {} description: OK - summary: Get Lsp Completions + summary: Create folder tags: - workspace toolbox - x-codegen-request-body-name: params - /workspace/{workspaceId}/{projectId}/toolbox/lsp/did-close: + /workspace/{workspaceId}/toolbox/files/permissions: post: - description: The document close notification is sent from the client to the - server when the document got closed in the client. - operationId: LspDidClose + description: Set file owner/group/permissions inside a workspace + operationId: FsSetFilePermissions parameters: - description: Workspace ID or Name in: path @@ -2092,32 +2099,38 @@ paths: required: true schema: type: string - - description: Project ID - in: path - name: projectId + - description: Path + in: query + name: path required: true schema: type: string - requestBody: - content: - '*/*': - schema: - $ref: '#/components/schemas/LspDocumentRequest' - description: LspDocumentRequest - required: true + - description: Owner + in: query + name: owner + schema: + type: string + - description: Group + in: query + name: group + schema: + type: string + - description: Mode + in: query + name: mode + schema: + type: string responses: "200": content: {} description: OK - summary: Call Lsp DidClose + summary: Set file owner/group/permissions tags: - workspace toolbox - x-codegen-request-body-name: params - /workspace/{workspaceId}/{projectId}/toolbox/lsp/did-open: + /workspace/{workspaceId}/toolbox/files/replace: post: - description: The document open notification is sent from the client to the server - to signal newly opened text documents. - operationId: LspDidOpen + description: Repleace text/pattern in mutilple files inside a workspace + operationId: FsReplaceInFiles parameters: - description: Workspace ID or Name in: path @@ -2125,31 +2138,30 @@ paths: required: true schema: type: string - - description: Project ID - in: path - name: projectId - required: true - schema: - type: string requestBody: content: '*/*': schema: - $ref: '#/components/schemas/LspDocumentRequest' - description: LspDocumentRequest + $ref: '#/components/schemas/ReplaceRequest' + description: ReplaceParams required: true responses: "200": - content: {} + content: + application/json: + schema: + items: + $ref: '#/components/schemas/ReplaceResult' + type: array description: OK - summary: Call Lsp DidOpen + summary: Repleace text/pattern in files tags: - workspace toolbox - x-codegen-request-body-name: params - /workspace/{workspaceId}/{projectId}/toolbox/lsp/document-symbols: + x-codegen-request-body-name: replace + /workspace/{workspaceId}/toolbox/files/search: get: - description: The document symbol request is sent from the client to the server. - operationId: LspDocumentSymbols + description: Search for files inside a workspace + operationId: FsSearchFiles parameters: - description: Workspace ID or Name in: path @@ -2157,27 +2169,15 @@ paths: required: true schema: type: string - - description: Project ID - in: path - name: projectId - required: true - schema: - type: string - - description: Language ID - in: query - name: languageId - required: true - schema: - type: string - - description: Path to project + - description: Path in: query - name: pathToProject + name: path required: true schema: type: string - - description: Document Uri + - description: Pattern in: query - name: uri + name: pattern required: true schema: type: string @@ -2186,17 +2186,15 @@ paths: content: application/json: schema: - items: - $ref: '#/components/schemas/LspSymbol' - type: array + $ref: '#/components/schemas/SearchFilesResponse' description: OK - summary: Call Lsp DocumentSymbols + summary: Search for files tags: - workspace toolbox - /workspace/{workspaceId}/{projectId}/toolbox/lsp/start: + /workspace/{workspaceId}/toolbox/files/upload: post: - description: Start Lsp server process inside workspace project - operationId: LspStart + description: Upload file inside a workspace + operationId: FsUploadFile parameters: - description: Workspace ID or Name in: path @@ -2204,31 +2202,29 @@ paths: required: true schema: type: string - - description: Project ID - in: path - name: projectId + - description: Path + in: query + name: path required: true schema: type: string requestBody: content: - '*/*': + multipart/form-data: schema: - $ref: '#/components/schemas/LspServerRequest' - description: LspServerRequest + $ref: '#/components/schemas/FsUploadFile_request' required: true responses: "200": content: {} description: OK - summary: Start Lsp server + summary: Upload file tags: - workspace toolbox - x-codegen-request-body-name: params - /workspace/{workspaceId}/{projectId}/toolbox/lsp/stop: + /workspace/{workspaceId}/toolbox/git/add: post: - description: Stop Lsp server process inside workspace project - operationId: LspStop + description: Add files to git commit + operationId: GitAddFiles parameters: - description: Workspace ID or Name in: path @@ -2236,32 +2232,25 @@ paths: required: true schema: type: string - - description: Project ID - in: path - name: projectId - required: true - schema: - type: string requestBody: content: '*/*': schema: - $ref: '#/components/schemas/LspServerRequest' - description: LspServerRequest + $ref: '#/components/schemas/GitAddRequest' + description: GitAddRequest required: true responses: "200": content: {} description: OK - summary: Stop Lsp server + summary: Add files tags: - workspace toolbox x-codegen-request-body-name: params - /workspace/{workspaceId}/{projectId}/toolbox/lsp/workspace-symbols: + /workspace/{workspaceId}/toolbox/git/branches: get: - description: The workspace symbol request is sent from the client to the server - to list project-wide symbols matching the query string. - operationId: LspWorkspaceSymbols + description: Get branch list from git repository inside a workspace + operationId: GitBranchList parameters: - description: Workspace ID or Name in: path @@ -2269,27 +2258,9 @@ paths: required: true schema: type: string - - description: Project ID - in: path - name: projectId - required: true - schema: - type: string - - description: Language ID - in: query - name: languageId - required: true - schema: - type: string - - description: Path to project - in: query - name: pathToProject - required: true - schema: - type: string - - description: Symbol Query + - description: Path to git repository in: query - name: query + name: path required: true schema: type: string @@ -2298,17 +2269,14 @@ paths: content: application/json: schema: - items: - $ref: '#/components/schemas/LspSymbol' - type: array + $ref: '#/components/schemas/ListBranchResponse' description: OK - summary: Call Lsp WorkspaceSymbols + summary: Get branch list tags: - workspace toolbox - /workspace/{workspaceId}/{projectId}/toolbox/process/execute: post: - description: Execute command synchronously inside workspace project - operationId: ProcessExecuteCommand + description: Create branch on git repository inside a workspace + operationId: GitCreateBranch parameters: - description: Workspace ID or Name in: path @@ -2316,9 +2284,29 @@ paths: required: true schema: type: string - - description: Project ID + requestBody: + content: + '*/*': + schema: + $ref: '#/components/schemas/GitBranchRequest' + description: GitBranchRequest + required: true + responses: + "201": + content: {} + description: Created + summary: Create branch + tags: + - workspace toolbox + x-codegen-request-body-name: params + /workspace/{workspaceId}/toolbox/git/clone: + post: + description: Clone git repository inside a workspace + operationId: GitCloneRepository + parameters: + - description: Workspace ID or Name in: path - name: projectId + name: workspaceId required: true schema: type: string @@ -2326,24 +2314,50 @@ paths: content: '*/*': schema: - $ref: '#/components/schemas/ExecuteRequest' - description: Execute command request + $ref: '#/components/schemas/GitCloneRequest' + description: GitCloneRequest + required: true + responses: + "200": + content: {} + description: OK + summary: Clone git repository + tags: + - workspace toolbox + x-codegen-request-body-name: params + /workspace/{workspaceId}/toolbox/git/commit: + post: + description: Commit changes to git repository inside a workspace + operationId: GitCommitChanges + parameters: + - description: Workspace ID or Name + in: path + name: workspaceId + required: true + schema: + type: string + requestBody: + content: + '*/*': + schema: + $ref: '#/components/schemas/GitCommitRequest' + description: GitCommitRequest required: true responses: "200": content: application/json: schema: - $ref: '#/components/schemas/ExecuteResponse' + $ref: '#/components/schemas/GitCommitResponse' description: OK - summary: Execute command + summary: Commit changes tags: - workspace toolbox x-codegen-request-body-name: params - /workspace/{workspaceId}/{projectId}/toolbox/process/session: + /workspace/{workspaceId}/toolbox/git/history: get: - description: List sessions inside workspace project - operationId: ListSessions + description: Get commit history from git repository inside a workspace + operationId: GitCommitHistory parameters: - description: Workspace ID or Name in: path @@ -2351,9 +2365,9 @@ paths: required: true schema: type: string - - description: Project ID - in: path - name: projectId + - description: Path to git repository + in: query + name: path required: true schema: type: string @@ -2363,15 +2377,16 @@ paths: application/json: schema: items: - $ref: '#/components/schemas/Session' + $ref: '#/components/schemas/GitCommitInfo' type: array description: OK - summary: List sessions + summary: Get commit history tags: - workspace toolbox + /workspace/{workspaceId}/toolbox/git/pull: post: - description: Create exec session inside workspace project - operationId: CreateSession + description: Pull changes from remote to git repository inside a workspace + operationId: GitPullChanges parameters: - description: Workspace ID or Name in: path @@ -2379,31 +2394,25 @@ paths: required: true schema: type: string - - description: Project ID - in: path - name: projectId - required: true - schema: - type: string requestBody: content: '*/*': schema: - $ref: '#/components/schemas/CreateSessionRequest' - description: Create session request + $ref: '#/components/schemas/GitRepoRequest' + description: Git pull request required: true responses: - "201": + "200": content: {} - description: Created - summary: Create exec session + description: OK + summary: Pull changes tags: - workspace toolbox x-codegen-request-body-name: params - /workspace/{workspaceId}/{projectId}/toolbox/process/session/{sessionId}: - delete: - description: Delete a session inside workspace project - operationId: DeleteSession + /workspace/{workspaceId}/toolbox/git/push: + post: + description: Push changes to remote from git repository inside a workspace + operationId: GitPushChanges parameters: - description: Workspace ID or Name in: path @@ -2411,31 +2420,53 @@ paths: required: true schema: type: string - - description: Project ID - in: path - name: projectId + requestBody: + content: + '*/*': + schema: + $ref: '#/components/schemas/GitRepoRequest' + description: Git push request required: true - schema: - type: string - - description: Session ID - in: path - name: sessionId + responses: + "200": + content: {} + description: OK + summary: Push changes + tags: + - workspace toolbox + x-codegen-request-body-name: params + /workspace/{workspaceId}/toolbox/git/status: + get: + description: Get status from git repository inside a workspace + operationId: GitGitStatus + parameters: + - description: Workspace ID or Name + in: path + name: workspaceId + required: true + schema: + type: string + - description: Path to git repository + in: query + name: path required: true schema: type: string responses: - "204": - content: {} - description: No Content - summary: Delete session + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/GitStatus' + description: OK + summary: Get git status tags: - workspace toolbox - /workspace/{workspaceId}/{projectId}/toolbox/process/session/{sessionId}/command/{commandId}/logs: - get: - description: |- - Get logs of a command inside a session inside workspace project - Connect with websocket to get a stream of the logs - operationId: GetSessionCommandLogs + /workspace/{workspaceId}/toolbox/lsp/completions: + post: + description: The Completion request is sent from the client to the server to + compute completion items at a given cursor position. + operationId: LspCompletions parameters: - description: Workspace ID or Name in: path @@ -2443,38 +2474,123 @@ paths: required: true schema: type: string - - description: Project ID + requestBody: + content: + '*/*': + schema: + $ref: '#/components/schemas/LspCompletionParams' + description: LspCompletionParams + required: true + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/CompletionList' + description: OK + summary: Get Lsp Completions + tags: + - workspace toolbox + x-codegen-request-body-name: params + /workspace/{workspaceId}/toolbox/lsp/did-close: + post: + description: The document close notification is sent from the client to the + server when the document got closed in the client. + operationId: LspDidClose + parameters: + - description: Workspace ID or Name in: path - name: projectId + name: workspaceId required: true schema: type: string - - description: Session ID + requestBody: + content: + '*/*': + schema: + $ref: '#/components/schemas/LspDocumentRequest' + description: LspDocumentRequest + required: true + responses: + "200": + content: {} + description: OK + summary: Call Lsp DidClose + tags: + - workspace toolbox + x-codegen-request-body-name: params + /workspace/{workspaceId}/toolbox/lsp/did-open: + post: + description: The document open notification is sent from the client to the server + to signal newly opened text documents. + operationId: LspDidOpen + parameters: + - description: Workspace ID or Name in: path - name: sessionId + name: workspaceId required: true schema: type: string - - description: Command ID + requestBody: + content: + '*/*': + schema: + $ref: '#/components/schemas/LspDocumentRequest' + description: LspDocumentRequest + required: true + responses: + "200": + content: {} + description: OK + summary: Call Lsp DidOpen + tags: + - workspace toolbox + x-codegen-request-body-name: params + /workspace/{workspaceId}/toolbox/lsp/document-symbols: + get: + description: The document symbol request is sent from the client to the server. + operationId: LspDocumentSymbols + parameters: + - description: Workspace ID or Name in: path - name: commandId + name: workspaceId + required: true + schema: + type: string + - description: Language ID + in: query + name: languageId + required: true + schema: + type: string + - description: Path to project + in: query + name: pathToProject + required: true + schema: + type: string + - description: Document Uri + in: query + name: uri required: true schema: type: string responses: "200": content: - '*/*': + application/json: schema: - type: string - description: command logs - summary: Get session command logs + items: + $ref: '#/components/schemas/LspSymbol' + type: array + description: OK + summary: Call Lsp DocumentSymbols tags: - workspace toolbox - /workspace/{workspaceId}/{projectId}/toolbox/process/session/{sessionId}/exec: + /workspace/{workspaceId}/toolbox/lsp/start: post: - description: Execute command inside a session inside workspace project - operationId: SessionExecuteCommand + description: Start Lsp server process inside a workspace + operationId: LspStart parameters: - description: Workspace ID or Name in: path @@ -2482,15 +2598,97 @@ paths: required: true schema: type: string - - description: Project ID + requestBody: + content: + '*/*': + schema: + $ref: '#/components/schemas/LspServerRequest' + description: LspServerRequest + required: true + responses: + "200": + content: {} + description: OK + summary: Start Lsp server + tags: + - workspace toolbox + x-codegen-request-body-name: params + /workspace/{workspaceId}/toolbox/lsp/stop: + post: + description: Stop Lsp server process inside a workspace + operationId: LspStop + parameters: + - description: Workspace ID or Name in: path - name: projectId + name: workspaceId required: true schema: type: string - - description: Session ID + requestBody: + content: + '*/*': + schema: + $ref: '#/components/schemas/LspServerRequest' + description: LspServerRequest + required: true + responses: + "200": + content: {} + description: OK + summary: Stop Lsp server + tags: + - workspace toolbox + x-codegen-request-body-name: params + /workspace/{workspaceId}/toolbox/lsp/workspace-symbols: + get: + description: The workspace symbol request is sent from the client to the server + to list project-wide symbols matching the query string. + operationId: LspWorkspaceSymbols + parameters: + - description: Workspace ID or Name in: path - name: sessionId + name: workspaceId + required: true + schema: + type: string + - description: Language ID + in: query + name: languageId + required: true + schema: + type: string + - description: Path to project + in: query + name: pathToProject + required: true + schema: + type: string + - description: Symbol Query + in: query + name: query + required: true + schema: + type: string + responses: + "200": + content: + application/json: + schema: + items: + $ref: '#/components/schemas/LspSymbol' + type: array + description: OK + summary: Call Lsp WorkspaceSymbols + tags: + - workspace toolbox + /workspace/{workspaceId}/toolbox/process/execute: + post: + description: Execute command synchronously inside a workspace + operationId: ProcessExecuteCommand + parameters: + - description: Workspace ID or Name + in: path + name: workspaceId required: true schema: type: string @@ -2498,7 +2696,7 @@ paths: content: '*/*': schema: - $ref: '#/components/schemas/SessionExecuteRequest' + $ref: '#/components/schemas/ExecuteRequest' description: Execute command request required: true responses: @@ -2506,16 +2704,16 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/SessionExecuteResponse' + $ref: '#/components/schemas/ExecuteResponse' description: OK - summary: Execute command in session + summary: Execute command tags: - workspace toolbox x-codegen-request-body-name: params - /workspace/{workspaceId}/{projectId}/toolbox/project-dir: + /workspace/{workspaceId}/toolbox/process/session: get: - description: Get project directory - operationId: GetProjectDir + description: List sessions inside workspace project + operationId: ListSessions parameters: - description: Workspace ID or Name in: path @@ -2523,60 +2721,198 @@ paths: required: true schema: type: string - - description: Project ID - in: path - name: projectId - required: true - schema: - type: string responses: "200": content: application/json: schema: - $ref: '#/components/schemas/ProjectDirResponse' + items: + $ref: '#/components/schemas/Session' + type: array description: OK - summary: Get project dir + summary: List sessions tags: - workspace toolbox -components: - schemas: - ApiKey: - example: - keyHash: keyHash - name: name - type: null - properties: - keyHash: - type: string - name: - description: Project or client name - type: string - type: - $ref: '#/components/schemas/apikey.ApiKeyType' - required: - - keyHash - - name - - type + post: + description: Create exec session inside workspace project + operationId: CreateSession + parameters: + - description: Workspace ID or Name + in: path + name: workspaceId + required: true + schema: + type: string + requestBody: + content: + '*/*': + schema: + $ref: '#/components/schemas/CreateSessionRequest' + description: Create session request + required: true + responses: + "201": + content: {} + description: Created + summary: Create exec session + tags: + - workspace toolbox + x-codegen-request-body-name: params + /workspace/{workspaceId}/toolbox/process/session/{sessionId}: + delete: + description: Delete a session inside workspace project + operationId: DeleteSession + parameters: + - description: Workspace ID or Name + in: path + name: workspaceId + required: true + schema: + type: string + - description: Session ID + in: path + name: sessionId + required: true + schema: + type: string + responses: + "204": + content: {} + description: No Content + summary: Delete session + tags: + - workspace toolbox + /workspace/{workspaceId}/toolbox/process/session/{sessionId}/command/{commandId}/logs: + get: + description: |- + Get logs of a command inside a session inside workspace project + Connect with websocket to get a stream of the logs + operationId: GetSessionCommandLogs + parameters: + - description: Workspace ID or Name + in: path + name: workspaceId + required: true + schema: + type: string + - description: Session ID + in: path + name: sessionId + required: true + schema: + type: string + - description: Command ID + in: path + name: commandId + required: true + schema: + type: string + responses: + "200": + content: + '*/*': + schema: + type: string + description: command logs + summary: Get session command logs + tags: + - workspace toolbox + /workspace/{workspaceId}/toolbox/process/session/{sessionId}/exec: + post: + description: Execute command inside a session inside workspace project + operationId: SessionExecuteCommand + parameters: + - description: Workspace ID or Name + in: path + name: workspaceId + required: true + schema: + type: string + - description: Session ID + in: path + name: sessionId + required: true + schema: + type: string + requestBody: + content: + '*/*': + schema: + $ref: '#/components/schemas/SessionExecuteRequest' + description: Execute command request + required: true + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/SessionExecuteResponse' + description: OK + summary: Execute command in session + tags: + - workspace toolbox + x-codegen-request-body-name: params + /workspace/{workspaceId}/toolbox/workspace-dir: + get: + description: Get workspace directory + operationId: GetWorkspaceDir + parameters: + - description: Workspace ID or Name + in: path + name: workspaceId + required: true + schema: + type: string + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/WorkspaceDirResponse' + description: OK + summary: Get workspace dir + tags: + - workspace toolbox +components: + schemas: + ApiKeyViewDTO: + example: + current: true + name: name + type: null + properties: + current: + type: boolean + name: + type: string + type: + $ref: '#/components/schemas/models.ApiKeyType' + required: + - current + - name + - type type: object - Build: + BuildConfig: + example: + cachedBuild: + image: image + user: user + devcontainer: + filePath: filePath + properties: + cachedBuild: + $ref: '#/components/schemas/CachedBuild' + devcontainer: + $ref: '#/components/schemas/DevcontainerConfig' + type: object + BuildDTO: example: - buildConfig: - cachedBuild: - image: image - user: user - devcontainer: - filePath: filePath - createdAt: createdAt image: image containerConfig: image: image user: user - prebuildId: prebuildId envVars: key: envVars - id: id - state: null repository: owner: owner path: path @@ -2588,6 +2924,31 @@ components: cloneTarget: null sha: sha url: url + buildConfig: + cachedBuild: + image: image + user: user + devcontainer: + filePath: filePath + createdAt: createdAt + prebuildId: prebuildId + lastJobId: lastJobId + lastJob: + createdAt: createdAt + metadata: metadata + resourceId: resourceId + action: null + runnerId: runnerId + id: id + state: null + error: error + resourceType: null + updatedAt: updatedAt + id: id + state: + name: null + error: error + updatedAt: updatedAt user: user updatedAt: updatedAt properties: @@ -2605,12 +2966,16 @@ components: type: string image: type: string + lastJob: + $ref: '#/components/schemas/Job' + lastJobId: + type: string prebuildId: type: string repository: $ref: '#/components/schemas/GitRepository' state: - $ref: '#/components/schemas/build.BuildState' + $ref: '#/components/schemas/ResourceState' updatedAt: type: string user: @@ -2620,24 +2985,10 @@ components: - createdAt - envVars - id - - prebuildId - repository - state - updatedAt type: object - BuildConfig: - example: - cachedBuild: - image: image - user: user - devcontainer: - filePath: filePath - properties: - cachedBuild: - $ref: '#/components/schemas/CachedBuild' - devcontainer: - $ref: '#/components/schemas/DevcontainerConfig' - type: object CachedBuild: example: image: image @@ -2776,10 +3127,10 @@ components: CreateBuildDTO: example: prebuildId: prebuildId - projectConfigName: projectConfigName envVars: key: envVars branch: branch + workspaceTemplateName: workspaceTemplateName properties: branch: type: string @@ -2789,12 +3140,12 @@ components: type: object prebuildId: type: string - projectConfigName: + workspaceTemplateName: type: string required: - branch - envVars - - projectConfigName + - workspaceTemplateName type: object CreatePrebuildDTO: example: @@ -2821,116 +3172,113 @@ components: required: - retention type: object - CreateProjectConfigDTO: + CreateRunnerDTO: example: - buildConfig: - cachedBuild: - image: image - user: user - devcontainer: - filePath: filePath - gitProviderConfigId: gitProviderConfigId - image: image - envVars: - key: envVars name: name - user: user - repositoryUrl: repositoryUrl + id: id properties: - buildConfig: - $ref: '#/components/schemas/BuildConfig' - envVars: - additionalProperties: - type: string - type: object - gitProviderConfigId: - type: string - image: + id: type: string name: type: string - repositoryUrl: - type: string - user: - type: string required: - - envVars + - id - name - - repositoryUrl type: object - CreateProjectDTO: + CreateRunnerResultDTO: example: - buildConfig: - cachedBuild: - image: image - user: user - devcontainer: - filePath: filePath - gitProviderConfigId: gitProviderConfigId - image: image - envVars: - key: envVars - name: name - source: - repository: - owner: owner - path: path + metadata: + runningJobs: 0 + runnerId: runnerId + providers: + - runnerName: runnerName + targetConfigManifest: + key: + defaultValue: defaultValue + options: + - options + - options + description: description + suggestions: + - suggestions + - suggestions + type: null + disabledPredicate: disabledPredicate + inputMasked: true + agentlessTarget: true name: name - id: id - source: source - prNumber: 0 - branch: branch - cloneTarget: null - sha: sha - url: url - user: user + runnerId: runnerId + label: label + version: version + - runnerName: runnerName + targetConfigManifest: + key: + defaultValue: defaultValue + options: + - options + - options + description: description + suggestions: + - suggestions + - suggestions + type: null + disabledPredicate: disabledPredicate + inputMasked: true + agentlessTarget: true + name: name + runnerId: runnerId + label: label + version: version + updatedAt: updatedAt + uptime: 6 + apiKey: apiKey + name: name + id: id properties: - buildConfig: - $ref: '#/components/schemas/BuildConfig' - envVars: - additionalProperties: - type: string - type: object - gitProviderConfigId: + apiKey: type: string - image: + id: type: string + metadata: + $ref: '#/components/schemas/RunnerMetadata' name: type: string - source: - $ref: '#/components/schemas/CreateProjectSourceDTO' - user: - type: string required: - - envVars + - apiKey + - id - name - - source type: object - CreateProjectSourceDTO: + CreateSessionRequest: example: - repository: - owner: owner - path: path - name: name - id: id - source: source - prNumber: 0 - branch: branch - cloneTarget: null - sha: sha - url: url + sessionId: sessionId properties: - repository: - $ref: '#/components/schemas/GitRepository' + sessionId: + type: string required: - - repository + - sessionId type: object - CreateProviderTargetDTO: + CreateTargetConfigDTO: example: name: name options: options providerInfo: + runnerName: runnerName + targetConfigManifest: + key: + defaultValue: defaultValue + options: + - options + - options + description: description + suggestions: + - suggestions + - suggestions + type: null + disabledPredicate: disabledPredicate + inputMasked: true + agentlessTarget: true name: name + runnerId: runnerId label: label version: version properties: @@ -2939,91 +3287,147 @@ components: options: type: string providerInfo: - $ref: '#/components/schemas/provider.ProviderInfo' + $ref: '#/components/schemas/ProviderInfo' required: - name - options - providerInfo type: object - CreateSessionRequest: + CreateTargetDTO: example: - sessionId: sessionId + name: name + targetConfigId: targetConfigId + id: id properties: - sessionId: + id: + type: string + name: + type: string + targetConfigId: type: string required: - - sessionId + - id + - name + - targetConfigId type: object CreateWorkspaceDTO: example: - projects: - - buildConfig: - cachedBuild: - image: image - user: user - devcontainer: - filePath: filePath - gitProviderConfigId: gitProviderConfigId - image: image - envVars: - key: envVars - name: name - source: - repository: - owner: owner - path: path - name: name - id: id - source: source - prNumber: 0 - branch: branch - cloneTarget: null - sha: sha - url: url - user: user - - buildConfig: - cachedBuild: - image: image - user: user - devcontainer: - filePath: filePath - gitProviderConfigId: gitProviderConfigId - image: image - envVars: - key: envVars - name: name - source: - repository: - owner: owner - path: path - name: name - id: id - source: source - prNumber: 0 - branch: branch - cloneTarget: null - sha: sha - url: url - user: user + buildConfig: + cachedBuild: + image: image + user: user + devcontainer: + filePath: filePath + gitProviderConfigId: gitProviderConfigId + image: image + targetId: targetId + envVars: + key: envVars name: name id: id - target: target + source: + repository: + owner: owner + path: path + name: name + id: id + source: source + prNumber: 0 + branch: branch + cloneTarget: null + sha: sha + url: url + user: user + labels: + key: labels properties: + buildConfig: + $ref: '#/components/schemas/BuildConfig' + envVars: + additionalProperties: + type: string + type: object + gitProviderConfigId: + type: string id: type: string + image: + type: string + labels: + additionalProperties: + type: string + type: object name: type: string - projects: - items: - $ref: '#/components/schemas/CreateProjectDTO' - type: array - target: + source: + $ref: '#/components/schemas/CreateWorkspaceSourceDTO' + targetId: + type: string + user: type: string required: + - envVars - id + - labels - name - - projects - - target + - source + - targetId + type: object + CreateWorkspaceSourceDTO: + example: + repository: + owner: owner + path: path + name: name + id: id + source: source + prNumber: 0 + branch: branch + cloneTarget: null + sha: sha + url: url + properties: + repository: + $ref: '#/components/schemas/GitRepository' + required: + - repository + type: object + CreateWorkspaceTemplateDTO: + example: + buildConfig: + cachedBuild: + image: image + user: user + devcontainer: + filePath: filePath + gitProviderConfigId: gitProviderConfigId + image: image + envVars: + key: envVars + name: name + user: user + repositoryUrl: repositoryUrl + properties: + buildConfig: + $ref: '#/components/schemas/BuildConfig' + envVars: + additionalProperties: + type: string + type: object + gitProviderConfigId: + type: string + image: + type: string + name: + type: string + repositoryUrl: + type: string + user: + type: string + required: + - envVars + - name + - repositoryUrl type: object DevcontainerConfig: example: @@ -3034,6 +3438,19 @@ components: required: - filePath type: object + EnvironmentVariable: + example: + value: value + key: key + properties: + key: + type: string + value: + type: string + required: + - key + - value + type: object ExecuteRequest: example: command: command @@ -3431,7 +3848,7 @@ components: type: object GitStatus: example: - behind: 6 + behind: 1 fileStatus: - extra: extra name: name @@ -3441,7 +3858,7 @@ components: name: name staging: null worktree: null - ahead: 0 + ahead: 6 branchPublished: true currentBranch: currentBranch properties: @@ -3482,22 +3899,61 @@ components: - name - username type: object - InstallProviderRequest: + Job: example: - downloadUrls: - key: downloadUrls - name: name + createdAt: createdAt + metadata: metadata + resourceId: resourceId + action: null + runnerId: runnerId + id: id + state: null + error: error + resourceType: null + updatedAt: updatedAt properties: - downloadUrls: - additionalProperties: - type: string - type: object - name: + action: + $ref: '#/components/schemas/models.JobAction' + createdAt: + type: string + error: + type: string + id: + type: string + metadata: + description: JSON encoded metadata + type: string + resourceId: + type: string + resourceType: + $ref: '#/components/schemas/ResourceType' + runnerId: + type: string + state: + $ref: '#/components/schemas/JobState' + updatedAt: type: string required: - - downloadUrls - - name + - action + - createdAt + - id + - resourceId + - resourceType + - state + - updatedAt type: object + JobState: + enum: + - pending + - running + - error + - success + type: string + x-enum-varnames: + - JobStatePending + - JobStateRunning + - JobStateError + - JobStateSuccess ListBranchResponse: example: branches: @@ -3733,14 +4189,12 @@ components: type: array required: - branch - - commitInterval - id - retention - triggerFiles type: object PrebuildDTO: example: - projectConfigName: projectConfigName commitInterval: 0 id: id branch: branch @@ -3748,6 +4202,7 @@ components: triggerFiles: - triggerFiles - triggerFiles + workspaceTemplateName: workspaceTemplateName properties: branch: type: string @@ -3755,279 +4210,305 @@ components: type: integer id: type: string - projectConfigName: - type: string retention: type: integer triggerFiles: items: type: string type: array + workspaceTemplateName: + type: string required: - branch - id - - projectConfigName - retention + - workspaceTemplateName type: object - ProfileData: + ProviderDTO: example: - envVars: - key: envVars + name: name + label: label + version: version + latest: true properties: - envVars: + label: + type: string + latest: + type: boolean + name: + type: string + version: + type: string + required: + - latest + - name + - version + type: object + ProviderInfo: + example: + runnerName: runnerName + targetConfigManifest: + key: + defaultValue: defaultValue + options: + - options + - options + description: description + suggestions: + - suggestions + - suggestions + type: null + disabledPredicate: disabledPredicate + inputMasked: true + agentlessTarget: true + name: name + runnerId: runnerId + label: label + version: version + properties: + agentlessTarget: + type: boolean + label: + type: string + name: + type: string + runnerId: + type: string + runnerName: + type: string + targetConfigManifest: additionalProperties: - type: string + $ref: '#/components/schemas/TargetConfigProperty' type: object + version: + type: string required: - - envVars + - name + - runnerId + - runnerName + - targetConfigManifest + - version type: object - Project: + ReplaceRequest: example: - buildConfig: - cachedBuild: - image: image - user: user - devcontainer: - filePath: filePath - gitProviderConfigId: gitProviderConfigId - image: image - envVars: - key: envVars - name: name - state: - gitStatus: - behind: 6 - fileStatus: - - extra: extra - name: name - staging: null - worktree: null - - extra: extra - name: name - staging: null - worktree: null - ahead: 0 - branchPublished: true - currentBranch: currentBranch - updatedAt: updatedAt - uptime: 1 - repository: - owner: owner - path: path - name: name - id: id - source: source - prNumber: 0 - branch: branch - cloneTarget: null - sha: sha - url: url - user: user - target: target - workspaceId: workspaceId + newValue: newValue + pattern: pattern + files: + - files + - files properties: - buildConfig: - $ref: '#/components/schemas/BuildConfig' - envVars: - additionalProperties: + files: + items: type: string - type: object - gitProviderConfigId: - type: string - image: - type: string - name: - type: string - repository: - $ref: '#/components/schemas/GitRepository' - state: - $ref: '#/components/schemas/ProjectState' - target: - type: string - user: + type: array + newValue: type: string - workspaceId: + pattern: type: string required: - - envVars - - image - - name - - repository - - target - - user - - workspaceId + - files + - newValue + - pattern type: object - ProjectConfig: + ReplaceResult: example: - prebuilds: - - commitInterval: 0 - id: id - branch: branch - retention: 6 - triggerFiles: - - triggerFiles - - triggerFiles - - commitInterval: 0 - id: id - branch: branch - retention: 6 - triggerFiles: - - triggerFiles - - triggerFiles - buildConfig: - cachedBuild: - image: image - user: user - devcontainer: - filePath: filePath - gitProviderConfigId: gitProviderConfigId - image: image - default: true - envVars: - key: envVars - name: name - user: user - repositoryUrl: repositoryUrl + file: file + success: true + error: error properties: - buildConfig: - $ref: '#/components/schemas/BuildConfig' - default: - type: boolean - envVars: - additionalProperties: - type: string - type: object - gitProviderConfigId: - type: string - image: - type: string - name: + error: type: string - prebuilds: - items: - $ref: '#/components/schemas/PrebuildConfig' - type: array - repositoryUrl: + file: type: string - user: + success: + type: boolean + type: object + RepositoryUrl: + example: + url: url + properties: + url: type: string required: - - default - - envVars - - image - - name - - repositoryUrl - - user + - url type: object - ProjectDirResponse: + ResourceState: example: - dir: dir + name: null + error: error + updatedAt: updatedAt properties: - dir: + error: + type: string + name: + $ref: '#/components/schemas/models.ResourceStateName' + updatedAt: type: string + required: + - name + - updatedAt type: object - ProjectInfo: + ResourceType: + enum: + - workspace + - target + - build + - runner + type: string + x-enum-varnames: + - ResourceTypeWorkspace + - ResourceTypeTarget + - ResourceTypeBuild + - ResourceTypeRunner + RunnerDTO: example: - providerMetadata: providerMetadata - isRunning: true - created: created + metadata: + runningJobs: 0 + runnerId: runnerId + providers: + - runnerName: runnerName + targetConfigManifest: + key: + defaultValue: defaultValue + options: + - options + - options + description: description + suggestions: + - suggestions + - suggestions + type: null + disabledPredicate: disabledPredicate + inputMasked: true + agentlessTarget: true + name: name + runnerId: runnerId + label: label + version: version + - runnerName: runnerName + targetConfigManifest: + key: + defaultValue: defaultValue + options: + - options + - options + description: description + suggestions: + - suggestions + - suggestions + type: null + disabledPredicate: disabledPredicate + inputMasked: true + agentlessTarget: true + name: name + runnerId: runnerId + label: label + version: version + updatedAt: updatedAt + uptime: 6 name: name - workspaceId: workspaceId + id: id + state: + name: null + error: error + updatedAt: updatedAt properties: - created: + id: type: string - isRunning: - type: boolean + metadata: + $ref: '#/components/schemas/RunnerMetadata' name: type: string - providerMetadata: - type: string - workspaceId: - type: string + state: + $ref: '#/components/schemas/ResourceState' required: - - created - - isRunning + - id - name - - workspaceId + - state type: object - ProjectState: + RunnerMetadata: example: - gitStatus: - behind: 6 - fileStatus: - - extra: extra - name: name - staging: null - worktree: null - - extra: extra - name: name - staging: null - worktree: null - ahead: 0 - branchPublished: true - currentBranch: currentBranch + runningJobs: 0 + runnerId: runnerId + providers: + - runnerName: runnerName + targetConfigManifest: + key: + defaultValue: defaultValue + options: + - options + - options + description: description + suggestions: + - suggestions + - suggestions + type: null + disabledPredicate: disabledPredicate + inputMasked: true + agentlessTarget: true + name: name + runnerId: runnerId + label: label + version: version + - runnerName: runnerName + targetConfigManifest: + key: + defaultValue: defaultValue + options: + - options + - options + description: description + suggestions: + - suggestions + - suggestions + type: null + disabledPredicate: disabledPredicate + inputMasked: true + agentlessTarget: true + name: name + runnerId: runnerId + label: label + version: version updatedAt: updatedAt - uptime: 1 + uptime: 6 properties: - gitStatus: - $ref: '#/components/schemas/GitStatus' + providers: + items: + $ref: '#/components/schemas/ProviderInfo' + type: array + runnerId: + type: string + runningJobs: + type: integer updatedAt: type: string uptime: type: integer required: + - providers + - runnerId - updatedAt - uptime type: object - Provider: + Sample: example: name: name - label: label - version: version + description: description + gitUrl: gitUrl properties: - label: - type: string - name: + description: type: string - version: + gitUrl: type: string - required: - - name - - version - type: object - ProviderTarget: - example: - isDefault: true - name: name - options: options - providerInfo: - name: name - label: label - version: version - properties: - isDefault: - type: boolean name: type: string - options: - description: JSON encoded map of options - type: string - providerInfo: - $ref: '#/components/schemas/provider.ProviderInfo' required: - - isDefault + - description + - gitUrl - name - - options - - providerInfo - type: object - ProviderTargetManifest: - additionalProperties: - $ref: '#/components/schemas/provider.ProviderTargetProperty' type: object - ReplaceRequest: + SearchFilesResponse: example: - newValue: newValue - pattern: pattern files: - files - files @@ -4036,77 +4517,20 @@ components: items: type: string type: array - newValue: - type: string - pattern: - type: string required: - files - - newValue - - pattern - type: object - ReplaceResult: - example: - file: file - success: true - error: error - properties: - error: - type: string - file: - type: string - success: - type: boolean type: object - RepositoryUrl: - example: - url: url - properties: - url: - type: string - required: - - url - type: object - Sample: - example: - name: name - description: description - gitUrl: gitUrl - properties: - description: - type: string - gitUrl: - type: string - name: - type: string - required: - - description - - gitUrl - - name - type: object - SearchFilesResponse: - example: - files: - - files - - files - properties: - files: - items: - type: string - type: array - required: - - files - type: object - ServerConfig: + ServerConfig: example: registryUrl: registryUrl localBuilderRegistryPort: 5 localBuilderRegistryImage: localBuilderRegistryImage - defaultProjectUser: defaultProjectUser builderRegistryServer: builderRegistryServer builderImage: builderImage + defaultWorkspaceImage: defaultWorkspaceImage apiPort: 0 headscalePort: 1 + localRunnerDisabled: true buildImageNamespace: buildImageNamespace serverDownloadUrl: serverDownloadUrl binariesPath: binariesPath @@ -4118,8 +4542,7 @@ components: maxBackups: 2 maxSize: 7 samplesIndexUrl: samplesIndexUrl - defaultProjectImage: defaultProjectImage - providersDir: providersDir + defaultWorkspaceUser: defaultWorkspaceUser id: id frps: protocol: protocol @@ -4136,9 +4559,9 @@ components: type: string builderRegistryServer: type: string - defaultProjectImage: + defaultWorkspaceImage: type: string - defaultProjectUser: + defaultWorkspaceUser: type: string frps: $ref: '#/components/schemas/FRPSConfig' @@ -4150,10 +4573,10 @@ components: type: string localBuilderRegistryPort: type: integer + localRunnerDisabled: + type: boolean logFile: $ref: '#/components/schemas/LogFileConfig' - providersDir: - type: string registryUrl: type: string samplesIndexUrl: @@ -4165,14 +4588,13 @@ components: - binariesPath - builderImage - builderRegistryServer - - defaultProjectImage - - defaultProjectUser + - defaultWorkspaceImage + - defaultWorkspaceUser - headscalePort - id - localBuilderRegistryImage - localBuilderRegistryPort - logFile - - providersDir - registryUrl - serverDownloadUrl type: object @@ -4253,31 +4675,6 @@ components: - providerId - token type: object - SetProjectState: - example: - gitStatus: - behind: 6 - fileStatus: - - extra: extra - name: name - staging: null - worktree: null - - extra: extra - name: name - staging: null - worktree: null - ahead: 0 - branchPublished: true - currentBranch: currentBranch - uptime: 0 - properties: - gitStatus: - $ref: '#/components/schemas/GitStatus' - uptime: - type: integer - required: - - uptime - type: object SigningMethod: enum: - ssh @@ -4306,130 +4703,248 @@ components: - Renamed - Copied - UpdatedButUnmerged - Workspace: + Target: example: - projects: - - buildConfig: - cachedBuild: - image: image - user: user - devcontainer: - filePath: filePath - gitProviderConfigId: gitProviderConfigId - image: image - envVars: - key: envVars - name: name - state: - gitStatus: - behind: 6 - fileStatus: - - extra: extra - name: name - staging: null - worktree: null - - extra: extra - name: name - staging: null - worktree: null - ahead: 0 - branchPublished: true - currentBranch: currentBranch - updatedAt: updatedAt - uptime: 1 - repository: - owner: owner - path: path - name: name - id: id - source: source - prNumber: 0 - branch: branch - cloneTarget: null - sha: sha - url: url - user: user - target: target - workspaceId: workspaceId - - buildConfig: - cachedBuild: - image: image - user: user - devcontainer: - filePath: filePath - gitProviderConfigId: gitProviderConfigId - image: image - envVars: - key: envVars + default: true + metadata: + targetId: targetId + updatedAt: updatedAt + uptime: 0 + targetConfig: + deleted: true name: name - state: - gitStatus: - behind: 6 - fileStatus: - - extra: extra - name: name - staging: null - worktree: null - - extra: extra - name: name - staging: null - worktree: null - ahead: 0 - branchPublished: true - currentBranch: currentBranch - updatedAt: updatedAt - uptime: 1 - repository: - owner: owner - path: path + options: options + id: id + providerInfo: + runnerName: runnerName + targetConfigManifest: + key: + defaultValue: defaultValue + options: + - options + - options + description: description + suggestions: + - suggestions + - suggestions + type: null + disabledPredicate: disabledPredicate + inputMasked: true + agentlessTarget: true name: name - id: id - source: source - prNumber: 0 - branch: branch - cloneTarget: null - sha: sha - url: url - user: user - target: target - workspaceId: workspaceId + runnerId: runnerId + label: label + version: version + providerMetadata: providerMetadata + lastJobId: lastJobId + lastJob: + createdAt: createdAt + metadata: metadata + resourceId: resourceId + action: null + runnerId: runnerId + id: id + state: null + error: error + resourceType: null + updatedAt: updatedAt + envVars: + key: envVars name: name + targetConfigId: targetConfigId id: id - target: target + workspaces: + - null + - null properties: + default: + type: boolean + envVars: + additionalProperties: + type: string + type: object id: type: string + lastJob: + $ref: '#/components/schemas/Job' + lastJobId: + type: string + metadata: + $ref: '#/components/schemas/TargetMetadata' name: type: string - projects: + providerMetadata: + type: string + targetConfig: + $ref: '#/components/schemas/TargetConfig' + targetConfigId: + type: string + workspaces: items: - $ref: '#/components/schemas/Project' + $ref: '#/components/schemas/Workspace' type: array - target: + required: + - default + - envVars + - id + - name + - targetConfig + - targetConfigId + - workspaces + type: object + TargetConfig: + example: + deleted: true + name: name + options: options + id: id + providerInfo: + runnerName: runnerName + targetConfigManifest: + key: + defaultValue: defaultValue + options: + - options + - options + description: description + suggestions: + - suggestions + - suggestions + type: null + disabledPredicate: disabledPredicate + inputMasked: true + agentlessTarget: true + name: name + runnerId: runnerId + label: label + version: version + properties: + deleted: + type: boolean + id: + type: string + name: + type: string + options: + description: JSON encoded map of options type: string + providerInfo: + $ref: '#/components/schemas/ProviderInfo' required: + - deleted - id - name - - projects - - target + - options + - providerInfo type: object - WorkspaceDTO: + TargetConfigManifest: + additionalProperties: + $ref: '#/components/schemas/TargetConfigProperty' + type: object + TargetConfigProperty: example: - projects: - - buildConfig: - cachedBuild: - image: image - user: user - devcontainer: - filePath: filePath - gitProviderConfigId: gitProviderConfigId - image: image - envVars: - key: envVars + defaultValue: defaultValue + options: + - options + - options + description: description + suggestions: + - suggestions + - suggestions + type: null + disabledPredicate: disabledPredicate + inputMasked: true + properties: + defaultValue: + description: |- + DefaultValue is converted into the appropriate type based on the Type + If the property is a FilePath, the DefaultValue is a path to a directory + type: string + description: + description: Brief description of the property + type: string + disabledPredicate: + description: |- + A regex string matched with the name of the target config to determine if the property should be disabled + If the regex matches the target config name, the property will be disabled + E.g. "^local$" will disable the property for the local target + type: string + inputMasked: + type: boolean + options: + description: Options is only used if the Type is TargetConfigPropertyTypeOption + items: + type: string + type: array + suggestions: + description: Suggestions is an optional list of auto-complete values to + assist the user while filling the field + items: + type: string + type: array + type: + $ref: '#/components/schemas/models.TargetConfigPropertyType' + type: object + TargetDTO: + example: + default: true + metadata: + targetId: targetId + updatedAt: updatedAt + uptime: 0 + targetConfig: + deleted: true name: name - state: + options: options + id: id + providerInfo: + runnerName: runnerName + targetConfigManifest: + key: + defaultValue: defaultValue + options: + - options + - options + description: description + suggestions: + - suggestions + - suggestions + type: null + disabledPredicate: disabledPredicate + inputMasked: true + agentlessTarget: true + name: name + runnerId: runnerId + label: label + version: version + providerMetadata: providerMetadata + lastJobId: lastJobId + lastJob: + createdAt: createdAt + metadata: metadata + resourceId: resourceId + action: null + runnerId: runnerId + id: id + state: null + error: error + resourceType: null + updatedAt: updatedAt + envVars: + key: envVars + name: name + targetConfigId: targetConfigId + id: id + state: + name: null + error: error + updatedAt: updatedAt + workspaces: + - gitProviderConfigId: gitProviderConfigId + image: image + metadata: gitStatus: - behind: 6 + behind: 1 fileStatus: - extra: extra name: name @@ -4439,11 +4954,17 @@ components: name: name staging: null worktree: null - ahead: 0 + ahead: 6 branchPublished: true currentBranch: currentBranch updatedAt: updatedAt - uptime: 1 + uptime: 5 + workspaceId: workspaceId + providerMetadata: providerMetadata + apiKey: apiKey + targetId: targetId + envVars: + key: envVars repository: owner: owner path: path @@ -4455,23 +4976,86 @@ components: cloneTarget: null sha: sha url: url - user: user - target: target - workspaceId: workspaceId - - buildConfig: + labels: + key: labels + target: + default: true + metadata: + targetId: targetId + updatedAt: updatedAt + uptime: 0 + targetConfig: + deleted: true + name: name + options: options + id: id + providerInfo: + runnerName: runnerName + targetConfigManifest: + key: + defaultValue: defaultValue + options: + - options + - options + description: description + suggestions: + - suggestions + - suggestions + type: null + disabledPredicate: disabledPredicate + inputMasked: true + agentlessTarget: true + name: name + runnerId: runnerId + label: label + version: version + providerMetadata: providerMetadata + lastJobId: lastJobId + lastJob: + createdAt: createdAt + metadata: metadata + resourceId: resourceId + action: null + runnerId: runnerId + id: id + state: null + error: error + resourceType: null + updatedAt: updatedAt + envVars: + key: envVars + name: name + targetConfigId: targetConfigId + id: id + workspaces: + - null + - null + buildConfig: cachedBuild: image: image user: user devcontainer: filePath: filePath - gitProviderConfigId: gitProviderConfigId - image: image - envVars: - key: envVars + lastJobId: lastJobId + lastJob: + createdAt: createdAt + metadata: metadata + resourceId: resourceId + action: null + runnerId: runnerId + id: id + state: null + error: error + resourceType: null + updatedAt: updatedAt name: name - state: + id: id + user: user + - gitProviderConfigId: gitProviderConfigId + image: image + metadata: gitStatus: - behind: 6 + behind: 1 fileStatus: - extra: extra name: name @@ -4481,11 +5065,17 @@ components: name: name staging: null worktree: null - ahead: 0 + ahead: 6 branchPublished: true currentBranch: currentBranch updatedAt: updatedAt - uptime: 1 + uptime: 5 + workspaceId: workspaceId + providerMetadata: providerMetadata + apiKey: apiKey + targetId: targetId + envVars: + key: envVars repository: owner: owner path: path @@ -4497,152 +5087,776 @@ components: cloneTarget: null sha: sha url: url - user: user - target: target - workspaceId: workspaceId - name: name - id: id - info: - projects: - - providerMetadata: providerMetadata - isRunning: true - created: created - name: name - workspaceId: workspaceId - - providerMetadata: providerMetadata - isRunning: true - created: created + labels: + key: labels + target: + default: true + metadata: + targetId: targetId + updatedAt: updatedAt + uptime: 0 + targetConfig: + deleted: true + name: name + options: options + id: id + providerInfo: + runnerName: runnerName + targetConfigManifest: + key: + defaultValue: defaultValue + options: + - options + - options + description: description + suggestions: + - suggestions + - suggestions + type: null + disabledPredicate: disabledPredicate + inputMasked: true + agentlessTarget: true + name: name + runnerId: runnerId + label: label + version: version + providerMetadata: providerMetadata + lastJobId: lastJobId + lastJob: + createdAt: createdAt + metadata: metadata + resourceId: resourceId + action: null + runnerId: runnerId + id: id + state: null + error: error + resourceType: null + updatedAt: updatedAt + envVars: + key: envVars name: name - workspaceId: workspaceId - providerMetadata: providerMetadata + targetConfigId: targetConfigId + id: id + workspaces: + - null + - null + buildConfig: + cachedBuild: + image: image + user: user + devcontainer: + filePath: filePath + lastJobId: lastJobId + lastJob: + createdAt: createdAt + metadata: metadata + resourceId: resourceId + action: null + runnerId: runnerId + id: id + state: null + error: error + resourceType: null + updatedAt: updatedAt name: name - target: target + id: id + user: user properties: + default: + type: boolean + envVars: + additionalProperties: + type: string + type: object id: type: string - info: - $ref: '#/components/schemas/WorkspaceInfo' + lastJob: + $ref: '#/components/schemas/Job' + lastJobId: + type: string + metadata: + $ref: '#/components/schemas/TargetMetadata' name: type: string - projects: + providerMetadata: + type: string + state: + $ref: '#/components/schemas/ResourceState' + targetConfig: + $ref: '#/components/schemas/TargetConfig' + targetConfigId: + type: string + workspaces: items: - $ref: '#/components/schemas/Project' + $ref: '#/components/schemas/Workspace' type: array - target: - type: string required: + - default + - envVars - id - name - - projects - - target + - state + - targetConfig + - targetConfigId + - workspaces type: object - WorkspaceInfo: + TargetMetadata: example: - projects: - - providerMetadata: providerMetadata - isRunning: true - created: created + targetId: targetId + updatedAt: updatedAt + uptime: 0 + properties: + targetId: + type: string + updatedAt: + type: string + uptime: + type: integer + required: + - targetId + - updatedAt + - uptime + type: object + UpdateJobState: + example: + errorMessage: errorMessage + state: null + properties: + errorMessage: + type: string + state: + $ref: '#/components/schemas/JobState' + required: + - state + type: object + UpdateRunnerMetadataDTO: + example: + runningJobs: 0 + providers: + - runnerName: runnerName + targetConfigManifest: + key: + defaultValue: defaultValue + options: + - options + - options + description: description + suggestions: + - suggestions + - suggestions + type: null + disabledPredicate: disabledPredicate + inputMasked: true + agentlessTarget: true name: name - workspaceId: workspaceId - - providerMetadata: providerMetadata - isRunning: true - created: created + runnerId: runnerId + label: label + version: version + - runnerName: runnerName + targetConfigManifest: + key: + defaultValue: defaultValue + options: + - options + - options + description: description + suggestions: + - suggestions + - suggestions + type: null + disabledPredicate: disabledPredicate + inputMasked: true + agentlessTarget: true name: name + runnerId: runnerId + label: label + version: version + uptime: 6 + properties: + providers: + items: + $ref: '#/components/schemas/ProviderInfo' + type: array + runningJobs: + type: integer + uptime: + type: integer + required: + - providers + - uptime + type: object + UpdateTargetMetadataDTO: + example: + uptime: 0 + properties: + uptime: + type: integer + required: + - uptime + type: object + UpdateTargetProviderMetadataDTO: + example: + metadata: metadata + properties: + metadata: + type: string + required: + - metadata + type: object + UpdateWorkspaceMetadataDTO: + example: + gitStatus: + behind: 1 + fileStatus: + - extra: extra + name: name + staging: null + worktree: null + - extra: extra + name: name + staging: null + worktree: null + ahead: 6 + branchPublished: true + currentBranch: currentBranch + uptime: 0 + properties: + gitStatus: + $ref: '#/components/schemas/GitStatus' + uptime: + type: integer + required: + - uptime + type: object + UpdateWorkspaceProviderMetadataDTO: + example: + metadata: metadata + properties: + metadata: + type: string + required: + - metadata + type: object + Workspace: + example: + gitProviderConfigId: gitProviderConfigId + image: image + metadata: + gitStatus: + behind: 1 + fileStatus: + - extra: extra + name: name + staging: null + worktree: null + - extra: extra + name: name + staging: null + worktree: null + ahead: 6 + branchPublished: true + currentBranch: currentBranch + updatedAt: updatedAt + uptime: 5 workspaceId: workspaceId providerMetadata: providerMetadata + apiKey: apiKey + targetId: targetId + envVars: + key: envVars + repository: + owner: owner + path: path + name: name + id: id + source: source + prNumber: 0 + branch: branch + cloneTarget: null + sha: sha + url: url + labels: + key: labels + target: + default: true + metadata: + targetId: targetId + updatedAt: updatedAt + uptime: 0 + targetConfig: + deleted: true + name: name + options: options + id: id + providerInfo: + runnerName: runnerName + targetConfigManifest: + key: + defaultValue: defaultValue + options: + - options + - options + description: description + suggestions: + - suggestions + - suggestions + type: null + disabledPredicate: disabledPredicate + inputMasked: true + agentlessTarget: true + name: name + runnerId: runnerId + label: label + version: version + providerMetadata: providerMetadata + lastJobId: lastJobId + lastJob: + createdAt: createdAt + metadata: metadata + resourceId: resourceId + action: null + runnerId: runnerId + id: id + state: null + error: error + resourceType: null + updatedAt: updatedAt + envVars: + key: envVars + name: name + targetConfigId: targetConfigId + id: id + workspaces: + - null + - null + buildConfig: + cachedBuild: + image: image + user: user + devcontainer: + filePath: filePath + lastJobId: lastJobId + lastJob: + createdAt: createdAt + metadata: metadata + resourceId: resourceId + action: null + runnerId: runnerId + id: id + state: null + error: error + resourceType: null + updatedAt: updatedAt name: name + id: id + user: user properties: + apiKey: + type: string + buildConfig: + $ref: '#/components/schemas/BuildConfig' + envVars: + additionalProperties: + type: string + type: object + gitProviderConfigId: + type: string + id: + type: string + image: + type: string + labels: + additionalProperties: + type: string + type: object + lastJob: + $ref: '#/components/schemas/Job' + lastJobId: + type: string + metadata: + $ref: '#/components/schemas/WorkspaceMetadata' name: type: string - projects: - items: - $ref: '#/components/schemas/ProjectInfo' - type: array providerMetadata: type: string + repository: + $ref: '#/components/schemas/GitRepository' + target: + $ref: '#/components/schemas/Target' + targetId: + type: string + user: + type: string required: + - apiKey + - envVars + - id + - image + - labels - name - - projects + - repository + - target + - targetId + - user type: object - apikey.ApiKeyType: - enum: - - client - - project - - workspace - type: string - x-enum-varnames: - - ApiKeyTypeClient - - ApiKeyTypeProject - - ApiKeyTypeWorkspace - build.BuildState: - enum: - - pending-run - - running - - error - - success - - published - - pending-delete - - pending-forced-delete - - deleting - type: string - x-enum-varnames: - - BuildStatePendingRun - - BuildStateRunning - - BuildStateError - - BuildStateSuccess - - BuildStatePublished - - BuildStatePendingDelete - - BuildStatePendingForcedDelete - - BuildStateDeleting - provider.ProviderInfo: + WorkspaceDTO: example: + gitProviderConfigId: gitProviderConfigId + image: image + metadata: + gitStatus: + behind: 1 + fileStatus: + - extra: extra + name: name + staging: null + worktree: null + - extra: extra + name: name + staging: null + worktree: null + ahead: 6 + branchPublished: true + currentBranch: currentBranch + updatedAt: updatedAt + uptime: 5 + workspaceId: workspaceId + providerMetadata: providerMetadata + apiKey: apiKey + targetId: targetId + envVars: + key: envVars + repository: + owner: owner + path: path + name: name + id: id + source: source + prNumber: 0 + branch: branch + cloneTarget: null + sha: sha + url: url + labels: + key: labels + target: + default: true + metadata: + targetId: targetId + updatedAt: updatedAt + uptime: 0 + targetConfig: + deleted: true + name: name + options: options + id: id + providerInfo: + runnerName: runnerName + targetConfigManifest: + key: + defaultValue: defaultValue + options: + - options + - options + description: description + suggestions: + - suggestions + - suggestions + type: null + disabledPredicate: disabledPredicate + inputMasked: true + agentlessTarget: true + name: name + runnerId: runnerId + label: label + version: version + providerMetadata: providerMetadata + lastJobId: lastJobId + lastJob: + createdAt: createdAt + metadata: metadata + resourceId: resourceId + action: null + runnerId: runnerId + id: id + state: null + error: error + resourceType: null + updatedAt: updatedAt + envVars: + key: envVars + name: name + targetConfigId: targetConfigId + id: id + workspaces: + - null + - null + buildConfig: + cachedBuild: + image: image + user: user + devcontainer: + filePath: filePath + lastJobId: lastJobId + lastJob: + createdAt: createdAt + metadata: metadata + resourceId: resourceId + action: null + runnerId: runnerId + id: id + state: null + error: error + resourceType: null + updatedAt: updatedAt name: name - label: label - version: version + id: id + state: + name: null + error: error + updatedAt: updatedAt + user: user properties: - label: + apiKey: type: string + buildConfig: + $ref: '#/components/schemas/BuildConfig' + envVars: + additionalProperties: + type: string + type: object + gitProviderConfigId: + type: string + id: + type: string + image: + type: string + labels: + additionalProperties: + type: string + type: object + lastJob: + $ref: '#/components/schemas/Job' + lastJobId: + type: string + metadata: + $ref: '#/components/schemas/WorkspaceMetadata' name: type: string - version: + providerMetadata: + type: string + repository: + $ref: '#/components/schemas/GitRepository' + state: + $ref: '#/components/schemas/ResourceState' + target: + $ref: '#/components/schemas/Target' + targetId: + type: string + user: type: string required: + - apiKey + - envVars + - id + - image + - labels - name - - version + - repository + - state + - target + - targetId + - user type: object - provider.ProviderTargetProperty: + WorkspaceDirResponse: + example: + dir: dir properties: - defaultValue: - description: |- - DefaultValue is converted into the appropriate type based on the Type - If the property is a FilePath, the DefaultValue is a path to a directory + dir: type: string - description: - description: Brief description of the property + type: object + WorkspaceMetadata: + example: + gitStatus: + behind: 1 + fileStatus: + - extra: extra + name: name + staging: null + worktree: null + - extra: extra + name: name + staging: null + worktree: null + ahead: 6 + branchPublished: true + currentBranch: currentBranch + updatedAt: updatedAt + uptime: 5 + workspaceId: workspaceId + properties: + gitStatus: + $ref: '#/components/schemas/GitStatus' + updatedAt: type: string - disabledPredicate: - description: |- - A regex string matched with the name of the target to determine if the property should be disabled - If the regex matches the target name, the property will be disabled - E.g. "^local$" will disable the property for the local target + uptime: + type: integer + workspaceId: type: string - inputMasked: + required: + - updatedAt + - uptime + - workspaceId + type: object + WorkspaceTemplate: + example: + prebuilds: + - commitInterval: 0 + id: id + branch: branch + retention: 6 + triggerFiles: + - triggerFiles + - triggerFiles + - commitInterval: 0 + id: id + branch: branch + retention: 6 + triggerFiles: + - triggerFiles + - triggerFiles + buildConfig: + cachedBuild: + image: image + user: user + devcontainer: + filePath: filePath + gitProviderConfigId: gitProviderConfigId + image: image + default: true + envVars: + key: envVars + name: name + user: user + labels: + key: labels + repositoryUrl: repositoryUrl + properties: + buildConfig: + $ref: '#/components/schemas/BuildConfig' + default: type: boolean - options: - description: Options is only used if the Type is ProviderTargetPropertyTypeOption - items: + envVars: + additionalProperties: type: string - type: array - suggestions: - description: Suggestions is an optional list of auto-complete values to - assist the user while filling the field - items: + type: object + gitProviderConfigId: + type: string + image: + type: string + labels: + additionalProperties: type: string + type: object + name: + type: string + prebuilds: + items: + $ref: '#/components/schemas/PrebuildConfig' type: array - type: - $ref: '#/components/schemas/provider.ProviderTargetPropertyType' + repositoryUrl: + type: string + user: + type: string + required: + - default + - envVars + - image + - labels + - name + - repositoryUrl + - user type: object - provider.ProviderTargetPropertyType: + models.ApiKeyType: + enum: + - client + - workspace + - target + - runner + type: string + x-enum-varnames: + - ApiKeyTypeClient + - ApiKeyTypeWorkspace + - ApiKeyTypeTarget + - ApiKeyTypeRunner + models.JobAction: + enum: + - create + - start + - stop + - restart + - delete + - force-delete + - run + - install-provider + - uninstall-provider + - update-provider + type: string + x-enum-varnames: + - JobActionCreate + - JobActionStart + - JobActionStop + - JobActionRestart + - JobActionDelete + - JobActionForceDelete + - JobActionRun + - JobActionInstallProvider + - JobActionUninstallProvider + - JobActionUpdateProvider + models.ResourceStateName: + enum: + - undefined + - pending-run + - running + - run-successful + - pending-create + - creating + - pending-start + - starting + - started + - pending-stop + - stopping + - stopped + - pending-restart + - error + - unresponsive + - pending-delete + - pending-forced-delete + - deleting + - deleted + type: string + x-enum-varnames: + - ResourceStateNameUndefined + - ResourceStateNamePendingRun + - ResourceStateNameRunning + - ResourceStateNameRunSuccessful + - ResourceStateNamePendingCreate + - ResourceStateNameCreating + - ResourceStateNamePendingStart + - ResourceStateNameStarting + - ResourceStateNameStarted + - ResourceStateNamePendingStop + - ResourceStateNameStopping + - ResourceStateNameStopped + - ResourceStateNamePendingRestart + - ResourceStateNameError + - ResourceStateNameUnresponsive + - ResourceStateNamePendingDelete + - ResourceStateNamePendingForcedDelete + - ResourceStateNameDeleting + - ResourceStateNameDeleted + models.TargetConfigPropertyType: enum: - string - option @@ -4652,12 +5866,12 @@ components: - file-path type: string x-enum-varnames: - - ProviderTargetPropertyTypeString - - ProviderTargetPropertyTypeOption - - ProviderTargetPropertyTypeBoolean - - ProviderTargetPropertyTypeInt - - ProviderTargetPropertyTypeFloat - - ProviderTargetPropertyTypeFilePath + - TargetConfigPropertyTypeString + - TargetConfigPropertyTypeOption + - TargetConfigPropertyTypeBoolean + - TargetConfigPropertyTypeInt + - TargetConfigPropertyTypeFloat + - TargetConfigPropertyTypeFilePath FsUploadFile_request: properties: file: diff --git a/pkg/apiclient/api_api_key.go b/pkg/apiclient/api_api_key.go index 412ac79c2c..de551cb9a9 100644 --- a/pkg/apiclient/api_api_key.go +++ b/pkg/apiclient/api_api_key.go @@ -22,27 +22,27 @@ import ( // ApiKeyAPIService ApiKeyAPI service type ApiKeyAPIService service -type ApiGenerateApiKeyRequest struct { +type ApiCreateApiKeyRequest struct { ctx context.Context ApiService *ApiKeyAPIService apiKeyName string } -func (r ApiGenerateApiKeyRequest) Execute() (string, *http.Response, error) { - return r.ApiService.GenerateApiKeyExecute(r) +func (r ApiCreateApiKeyRequest) Execute() (string, *http.Response, error) { + return r.ApiService.CreateApiKeyExecute(r) } /* -GenerateApiKey Generate an API key +CreateApiKey Create an API key -Generate an API key +Create an API key @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @param apiKeyName API key name - @return ApiGenerateApiKeyRequest + @return ApiCreateApiKeyRequest */ -func (a *ApiKeyAPIService) GenerateApiKey(ctx context.Context, apiKeyName string) ApiGenerateApiKeyRequest { - return ApiGenerateApiKeyRequest{ +func (a *ApiKeyAPIService) CreateApiKey(ctx context.Context, apiKeyName string) ApiCreateApiKeyRequest { + return ApiCreateApiKeyRequest{ ApiService: a, ctx: ctx, apiKeyName: apiKeyName, @@ -52,7 +52,7 @@ func (a *ApiKeyAPIService) GenerateApiKey(ctx context.Context, apiKeyName string // Execute executes the request // // @return string -func (a *ApiKeyAPIService) GenerateApiKeyExecute(r ApiGenerateApiKeyRequest) (string, *http.Response, error) { +func (a *ApiKeyAPIService) CreateApiKeyExecute(r ApiCreateApiKeyRequest) (string, *http.Response, error) { var ( localVarHTTPMethod = http.MethodPost localVarPostBody interface{} @@ -60,7 +60,7 @@ func (a *ApiKeyAPIService) GenerateApiKeyExecute(r ApiGenerateApiKeyRequest) (st localVarReturnValue string ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "ApiKeyAPIService.GenerateApiKey") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "ApiKeyAPIService.CreateApiKey") if err != nil { return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } @@ -140,47 +140,48 @@ func (a *ApiKeyAPIService) GenerateApiKeyExecute(r ApiGenerateApiKeyRequest) (st return localVarReturnValue, localVarHTTPResponse, nil } -type ApiListClientApiKeysRequest struct { +type ApiDeleteApiKeyRequest struct { ctx context.Context ApiService *ApiKeyAPIService + apiKeyName string } -func (r ApiListClientApiKeysRequest) Execute() ([]ApiKey, *http.Response, error) { - return r.ApiService.ListClientApiKeysExecute(r) +func (r ApiDeleteApiKeyRequest) Execute() (*http.Response, error) { + return r.ApiService.DeleteApiKeyExecute(r) } /* -ListClientApiKeys List API keys +DeleteApiKey Delete API key -List API keys +Delete API key @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). - @return ApiListClientApiKeysRequest + @param apiKeyName API key name + @return ApiDeleteApiKeyRequest */ -func (a *ApiKeyAPIService) ListClientApiKeys(ctx context.Context) ApiListClientApiKeysRequest { - return ApiListClientApiKeysRequest{ +func (a *ApiKeyAPIService) DeleteApiKey(ctx context.Context, apiKeyName string) ApiDeleteApiKeyRequest { + return ApiDeleteApiKeyRequest{ ApiService: a, ctx: ctx, + apiKeyName: apiKeyName, } } // Execute executes the request -// -// @return []ApiKey -func (a *ApiKeyAPIService) ListClientApiKeysExecute(r ApiListClientApiKeysRequest) ([]ApiKey, *http.Response, error) { +func (a *ApiKeyAPIService) DeleteApiKeyExecute(r ApiDeleteApiKeyRequest) (*http.Response, error) { var ( - localVarHTTPMethod = http.MethodGet - localVarPostBody interface{} - formFiles []formFile - localVarReturnValue []ApiKey + localVarHTTPMethod = http.MethodDelete + localVarPostBody interface{} + formFiles []formFile ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "ApiKeyAPIService.ListClientApiKeys") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "ApiKeyAPIService.DeleteApiKey") if err != nil { - return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} + return nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/apikey" + localVarPath := localBasePath + "/apikey/{apiKeyName}" + localVarPath = strings.Replace(localVarPath, "{"+"apiKeyName"+"}", url.PathEscape(parameterValueToString(r.apiKeyName, "apiKeyName")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -196,7 +197,7 @@ func (a *ApiKeyAPIService) ListClientApiKeysExecute(r ApiListClientApiKeysReques } // to determine the Accept header - localVarHTTPHeaderAccepts := []string{"application/json"} + localVarHTTPHeaderAccepts := []string{} // set Accept header localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) @@ -219,19 +220,19 @@ func (a *ApiKeyAPIService) ListClientApiKeysExecute(r ApiListClientApiKeysReques } req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles) if err != nil { - return localVarReturnValue, nil, err + return nil, err } localVarHTTPResponse, err := a.client.callAPI(req) if err != nil || localVarHTTPResponse == nil { - return localVarReturnValue, localVarHTTPResponse, err + return localVarHTTPResponse, err } localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) localVarHTTPResponse.Body.Close() localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) if err != nil { - return localVarReturnValue, localVarHTTPResponse, err + return localVarHTTPResponse, err } if localVarHTTPResponse.StatusCode >= 300 { @@ -239,63 +240,53 @@ func (a *ApiKeyAPIService) ListClientApiKeysExecute(r ApiListClientApiKeysReques body: localVarBody, error: localVarHTTPResponse.Status, } - return localVarReturnValue, localVarHTTPResponse, newErr - } - - err = a.client.decode(&localVarReturnValue, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) - if err != nil { - newErr := &GenericOpenAPIError{ - body: localVarBody, - error: err.Error(), - } - return localVarReturnValue, localVarHTTPResponse, newErr + return localVarHTTPResponse, newErr } - return localVarReturnValue, localVarHTTPResponse, nil + return localVarHTTPResponse, nil } -type ApiRevokeApiKeyRequest struct { +type ApiListClientApiKeysRequest struct { ctx context.Context ApiService *ApiKeyAPIService - apiKeyName string } -func (r ApiRevokeApiKeyRequest) Execute() (*http.Response, error) { - return r.ApiService.RevokeApiKeyExecute(r) +func (r ApiListClientApiKeysRequest) Execute() ([]ApiKeyViewDTO, *http.Response, error) { + return r.ApiService.ListClientApiKeysExecute(r) } /* -RevokeApiKey Revoke API key +ListClientApiKeys List API keys -Revoke API key +List API keys @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). - @param apiKeyName API key name - @return ApiRevokeApiKeyRequest + @return ApiListClientApiKeysRequest */ -func (a *ApiKeyAPIService) RevokeApiKey(ctx context.Context, apiKeyName string) ApiRevokeApiKeyRequest { - return ApiRevokeApiKeyRequest{ +func (a *ApiKeyAPIService) ListClientApiKeys(ctx context.Context) ApiListClientApiKeysRequest { + return ApiListClientApiKeysRequest{ ApiService: a, ctx: ctx, - apiKeyName: apiKeyName, } } // Execute executes the request -func (a *ApiKeyAPIService) RevokeApiKeyExecute(r ApiRevokeApiKeyRequest) (*http.Response, error) { +// +// @return []ApiKeyViewDTO +func (a *ApiKeyAPIService) ListClientApiKeysExecute(r ApiListClientApiKeysRequest) ([]ApiKeyViewDTO, *http.Response, error) { var ( - localVarHTTPMethod = http.MethodDelete - localVarPostBody interface{} - formFiles []formFile + localVarHTTPMethod = http.MethodGet + localVarPostBody interface{} + formFiles []formFile + localVarReturnValue []ApiKeyViewDTO ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "ApiKeyAPIService.RevokeApiKey") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "ApiKeyAPIService.ListClientApiKeys") if err != nil { - return nil, &GenericOpenAPIError{error: err.Error()} + return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/apikey/{apiKeyName}" - localVarPath = strings.Replace(localVarPath, "{"+"apiKeyName"+"}", url.PathEscape(parameterValueToString(r.apiKeyName, "apiKeyName")), -1) + localVarPath := localBasePath + "/apikey" localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -311,7 +302,7 @@ func (a *ApiKeyAPIService) RevokeApiKeyExecute(r ApiRevokeApiKeyRequest) (*http. } // to determine the Accept header - localVarHTTPHeaderAccepts := []string{} + localVarHTTPHeaderAccepts := []string{"application/json"} // set Accept header localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) @@ -334,19 +325,19 @@ func (a *ApiKeyAPIService) RevokeApiKeyExecute(r ApiRevokeApiKeyRequest) (*http. } req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles) if err != nil { - return nil, err + return localVarReturnValue, nil, err } localVarHTTPResponse, err := a.client.callAPI(req) if err != nil || localVarHTTPResponse == nil { - return localVarHTTPResponse, err + return localVarReturnValue, localVarHTTPResponse, err } localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) localVarHTTPResponse.Body.Close() localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) if err != nil { - return localVarHTTPResponse, err + return localVarReturnValue, localVarHTTPResponse, err } if localVarHTTPResponse.StatusCode >= 300 { @@ -354,8 +345,17 @@ func (a *ApiKeyAPIService) RevokeApiKeyExecute(r ApiRevokeApiKeyRequest) (*http. body: localVarBody, error: localVarHTTPResponse.Status, } - return localVarHTTPResponse, newErr + return localVarReturnValue, localVarHTTPResponse, newErr } - return localVarHTTPResponse, nil + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: err.Error(), + } + return localVarReturnValue, localVarHTTPResponse, newErr + } + + return localVarReturnValue, localVarHTTPResponse, nil } diff --git a/pkg/apiclient/api_build.go b/pkg/apiclient/api_build.go index f3ed813ff3..ed9229eec8 100644 --- a/pkg/apiclient/api_build.go +++ b/pkg/apiclient/api_build.go @@ -492,27 +492,27 @@ func (a *BuildAPIService) DeleteBuildsFromPrebuildExecute(r ApiDeleteBuildsFromP return localVarHTTPResponse, nil } -type ApiGetBuildRequest struct { +type ApiFindBuildRequest struct { ctx context.Context ApiService *BuildAPIService buildId string } -func (r ApiGetBuildRequest) Execute() (*Build, *http.Response, error) { - return r.ApiService.GetBuildExecute(r) +func (r ApiFindBuildRequest) Execute() (*BuildDTO, *http.Response, error) { + return r.ApiService.FindBuildExecute(r) } /* -GetBuild Get build data +FindBuild Find build -Get build data +Find build @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @param buildId Build ID - @return ApiGetBuildRequest + @return ApiFindBuildRequest */ -func (a *BuildAPIService) GetBuild(ctx context.Context, buildId string) ApiGetBuildRequest { - return ApiGetBuildRequest{ +func (a *BuildAPIService) FindBuild(ctx context.Context, buildId string) ApiFindBuildRequest { + return ApiFindBuildRequest{ ApiService: a, ctx: ctx, buildId: buildId, @@ -521,16 +521,16 @@ func (a *BuildAPIService) GetBuild(ctx context.Context, buildId string) ApiGetBu // Execute executes the request // -// @return Build -func (a *BuildAPIService) GetBuildExecute(r ApiGetBuildRequest) (*Build, *http.Response, error) { +// @return BuildDTO +func (a *BuildAPIService) FindBuildExecute(r ApiFindBuildRequest) (*BuildDTO, *http.Response, error) { var ( localVarHTTPMethod = http.MethodGet localVarPostBody interface{} formFiles []formFile - localVarReturnValue *Build + localVarReturnValue *BuildDTO ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "BuildAPIService.GetBuild") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "BuildAPIService.FindBuild") if err != nil { return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } @@ -615,7 +615,7 @@ type ApiListBuildsRequest struct { ApiService *BuildAPIService } -func (r ApiListBuildsRequest) Execute() ([]Build, *http.Response, error) { +func (r ApiListBuildsRequest) Execute() ([]BuildDTO, *http.Response, error) { return r.ApiService.ListBuildsExecute(r) } @@ -636,13 +636,13 @@ func (a *BuildAPIService) ListBuilds(ctx context.Context) ApiListBuildsRequest { // Execute executes the request // -// @return []Build -func (a *BuildAPIService) ListBuildsExecute(r ApiListBuildsRequest) ([]Build, *http.Response, error) { +// @return []BuildDTO +func (a *BuildAPIService) ListBuildsExecute(r ApiListBuildsRequest) ([]BuildDTO, *http.Response, error) { var ( localVarHTTPMethod = http.MethodGet localVarPostBody interface{} formFiles []formFile - localVarReturnValue []Build + localVarReturnValue []BuildDTO ) localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "BuildAPIService.ListBuilds") @@ -723,3 +723,121 @@ func (a *BuildAPIService) ListBuildsExecute(r ApiListBuildsRequest) ([]Build, *h return localVarReturnValue, localVarHTTPResponse, nil } + +type ApiListSuccessfulBuildsRequest struct { + ctx context.Context + ApiService *BuildAPIService + repoUrl string +} + +func (r ApiListSuccessfulBuildsRequest) Execute() ([]BuildDTO, *http.Response, error) { + return r.ApiService.ListSuccessfulBuildsExecute(r) +} + +/* +ListSuccessfulBuilds List successful builds for Git repository + +List successful builds for Git repository + + @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + @param repoUrl Repository URL + @return ApiListSuccessfulBuildsRequest +*/ +func (a *BuildAPIService) ListSuccessfulBuilds(ctx context.Context, repoUrl string) ApiListSuccessfulBuildsRequest { + return ApiListSuccessfulBuildsRequest{ + ApiService: a, + ctx: ctx, + repoUrl: repoUrl, + } +} + +// Execute executes the request +// +// @return []BuildDTO +func (a *BuildAPIService) ListSuccessfulBuildsExecute(r ApiListSuccessfulBuildsRequest) ([]BuildDTO, *http.Response, error) { + var ( + localVarHTTPMethod = http.MethodGet + localVarPostBody interface{} + formFiles []formFile + localVarReturnValue []BuildDTO + ) + + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "BuildAPIService.ListSuccessfulBuilds") + if err != nil { + return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} + } + + localVarPath := localBasePath + "/build/successful/{repoUrl}" + localVarPath = strings.Replace(localVarPath, "{"+"repoUrl"+"}", url.PathEscape(parameterValueToString(r.repoUrl, "repoUrl")), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHTTPContentTypes := []string{} + + // set Content-Type header + localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes) + if localVarHTTPContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHTTPContentType + } + + // to determine the Accept header + localVarHTTPHeaderAccepts := []string{"application/json"} + + // set Accept header + localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) + if localVarHTTPHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept + } + if r.ctx != nil { + // API Key Authentication + if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { + if apiKey, ok := auth["Bearer"]; ok { + var key string + if apiKey.Prefix != "" { + key = apiKey.Prefix + " " + apiKey.Key + } else { + key = apiKey.Key + } + localVarHeaderParams["Authorization"] = key + } + } + } + req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHTTPResponse, err := a.client.callAPI(req) + if err != nil || localVarHTTPResponse == nil { + return localVarReturnValue, localVarHTTPResponse, err + } + + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) + localVarHTTPResponse.Body.Close() + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) + if err != nil { + return localVarReturnValue, localVarHTTPResponse, err + } + + if localVarHTTPResponse.StatusCode >= 300 { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: localVarHTTPResponse.Status, + } + return localVarReturnValue, localVarHTTPResponse, newErr + } + + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: err.Error(), + } + return localVarReturnValue, localVarHTTPResponse, newErr + } + + return localVarReturnValue, localVarHTTPResponse, nil +} diff --git a/pkg/apiclient/api_container_registry.go b/pkg/apiclient/api_container_registry.go index fd1a8876ba..e156483b2f 100644 --- a/pkg/apiclient/api_container_registry.go +++ b/pkg/apiclient/api_container_registry.go @@ -22,27 +22,34 @@ import ( // ContainerRegistryAPIService ContainerRegistryAPI service type ContainerRegistryAPIService service -type ApiGetContainerRegistryRequest struct { - ctx context.Context - ApiService *ContainerRegistryAPIService - server string +type ApiFindContainerRegistryRequest struct { + ctx context.Context + ApiService *ContainerRegistryAPIService + server string + workspaceId *string } -func (r ApiGetContainerRegistryRequest) Execute() (*ContainerRegistry, *http.Response, error) { - return r.ApiService.GetContainerRegistryExecute(r) +// Workspace ID or Name +func (r ApiFindContainerRegistryRequest) WorkspaceId(workspaceId string) ApiFindContainerRegistryRequest { + r.workspaceId = &workspaceId + return r +} + +func (r ApiFindContainerRegistryRequest) Execute() (*ContainerRegistry, *http.Response, error) { + return r.ApiService.FindContainerRegistryExecute(r) } /* -GetContainerRegistry Get container registry credentials +FindContainerRegistry Find container registry -Get container registry credentials +Find container registry @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). - @param server Container Registry server name - @return ApiGetContainerRegistryRequest + @param server Container registry server + @return ApiFindContainerRegistryRequest */ -func (a *ContainerRegistryAPIService) GetContainerRegistry(ctx context.Context, server string) ApiGetContainerRegistryRequest { - return ApiGetContainerRegistryRequest{ +func (a *ContainerRegistryAPIService) FindContainerRegistry(ctx context.Context, server string) ApiFindContainerRegistryRequest { + return ApiFindContainerRegistryRequest{ ApiService: a, ctx: ctx, server: server, @@ -52,7 +59,7 @@ func (a *ContainerRegistryAPIService) GetContainerRegistry(ctx context.Context, // Execute executes the request // // @return ContainerRegistry -func (a *ContainerRegistryAPIService) GetContainerRegistryExecute(r ApiGetContainerRegistryRequest) (*ContainerRegistry, *http.Response, error) { +func (a *ContainerRegistryAPIService) FindContainerRegistryExecute(r ApiFindContainerRegistryRequest) (*ContainerRegistry, *http.Response, error) { var ( localVarHTTPMethod = http.MethodGet localVarPostBody interface{} @@ -60,7 +67,7 @@ func (a *ContainerRegistryAPIService) GetContainerRegistryExecute(r ApiGetContai localVarReturnValue *ContainerRegistry ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "ContainerRegistryAPIService.GetContainerRegistry") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "ContainerRegistryAPIService.FindContainerRegistry") if err != nil { return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } @@ -72,120 +79,9 @@ func (a *ContainerRegistryAPIService) GetContainerRegistryExecute(r ApiGetContai localVarQueryParams := url.Values{} localVarFormParams := url.Values{} - // to determine the Content-Type header - localVarHTTPContentTypes := []string{} - - // set Content-Type header - localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes) - if localVarHTTPContentType != "" { - localVarHeaderParams["Content-Type"] = localVarHTTPContentType - } - - // to determine the Accept header - localVarHTTPHeaderAccepts := []string{"application/json"} - - // set Accept header - localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) - if localVarHTTPHeaderAccept != "" { - localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept - } - if r.ctx != nil { - // API Key Authentication - if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { - if apiKey, ok := auth["Bearer"]; ok { - var key string - if apiKey.Prefix != "" { - key = apiKey.Prefix + " " + apiKey.Key - } else { - key = apiKey.Key - } - localVarHeaderParams["Authorization"] = key - } - } - } - req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles) - if err != nil { - return localVarReturnValue, nil, err - } - - localVarHTTPResponse, err := a.client.callAPI(req) - if err != nil || localVarHTTPResponse == nil { - return localVarReturnValue, localVarHTTPResponse, err - } - - localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) - localVarHTTPResponse.Body.Close() - localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) - if err != nil { - return localVarReturnValue, localVarHTTPResponse, err - } - - if localVarHTTPResponse.StatusCode >= 300 { - newErr := &GenericOpenAPIError{ - body: localVarBody, - error: localVarHTTPResponse.Status, - } - return localVarReturnValue, localVarHTTPResponse, newErr + if r.workspaceId != nil { + parameterAddToHeaderOrQuery(localVarQueryParams, "workspaceId", r.workspaceId, "") } - - err = a.client.decode(&localVarReturnValue, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) - if err != nil { - newErr := &GenericOpenAPIError{ - body: localVarBody, - error: err.Error(), - } - return localVarReturnValue, localVarHTTPResponse, newErr - } - - return localVarReturnValue, localVarHTTPResponse, nil -} - -type ApiListContainerRegistriesRequest struct { - ctx context.Context - ApiService *ContainerRegistryAPIService -} - -func (r ApiListContainerRegistriesRequest) Execute() ([]ContainerRegistry, *http.Response, error) { - return r.ApiService.ListContainerRegistriesExecute(r) -} - -/* -ListContainerRegistries List container registries - -List container registries - - @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). - @return ApiListContainerRegistriesRequest -*/ -func (a *ContainerRegistryAPIService) ListContainerRegistries(ctx context.Context) ApiListContainerRegistriesRequest { - return ApiListContainerRegistriesRequest{ - ApiService: a, - ctx: ctx, - } -} - -// Execute executes the request -// -// @return []ContainerRegistry -func (a *ContainerRegistryAPIService) ListContainerRegistriesExecute(r ApiListContainerRegistriesRequest) ([]ContainerRegistry, *http.Response, error) { - var ( - localVarHTTPMethod = http.MethodGet - localVarPostBody interface{} - formFiles []formFile - localVarReturnValue []ContainerRegistry - ) - - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "ContainerRegistryAPIService.ListContainerRegistries") - if err != nil { - return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} - } - - localVarPath := localBasePath + "/container-registry" - - localVarHeaderParams := make(map[string]string) - localVarQueryParams := url.Values{} - localVarFormParams := url.Values{} - // to determine the Content-Type header localVarHTTPContentTypes := []string{} @@ -253,227 +149,3 @@ func (a *ContainerRegistryAPIService) ListContainerRegistriesExecute(r ApiListCo return localVarReturnValue, localVarHTTPResponse, nil } - -type ApiRemoveContainerRegistryRequest struct { - ctx context.Context - ApiService *ContainerRegistryAPIService - server string -} - -func (r ApiRemoveContainerRegistryRequest) Execute() (*http.Response, error) { - return r.ApiService.RemoveContainerRegistryExecute(r) -} - -/* -RemoveContainerRegistry Remove a container registry credentials - -Remove a container registry credentials - - @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). - @param server Container Registry server name - @return ApiRemoveContainerRegistryRequest -*/ -func (a *ContainerRegistryAPIService) RemoveContainerRegistry(ctx context.Context, server string) ApiRemoveContainerRegistryRequest { - return ApiRemoveContainerRegistryRequest{ - ApiService: a, - ctx: ctx, - server: server, - } -} - -// Execute executes the request -func (a *ContainerRegistryAPIService) RemoveContainerRegistryExecute(r ApiRemoveContainerRegistryRequest) (*http.Response, error) { - var ( - localVarHTTPMethod = http.MethodDelete - localVarPostBody interface{} - formFiles []formFile - ) - - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "ContainerRegistryAPIService.RemoveContainerRegistry") - if err != nil { - return nil, &GenericOpenAPIError{error: err.Error()} - } - - localVarPath := localBasePath + "/container-registry/{server}" - localVarPath = strings.Replace(localVarPath, "{"+"server"+"}", url.PathEscape(parameterValueToString(r.server, "server")), -1) - - localVarHeaderParams := make(map[string]string) - localVarQueryParams := url.Values{} - localVarFormParams := url.Values{} - - // to determine the Content-Type header - localVarHTTPContentTypes := []string{} - - // set Content-Type header - localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes) - if localVarHTTPContentType != "" { - localVarHeaderParams["Content-Type"] = localVarHTTPContentType - } - - // to determine the Accept header - localVarHTTPHeaderAccepts := []string{} - - // set Accept header - localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) - if localVarHTTPHeaderAccept != "" { - localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept - } - if r.ctx != nil { - // API Key Authentication - if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { - if apiKey, ok := auth["Bearer"]; ok { - var key string - if apiKey.Prefix != "" { - key = apiKey.Prefix + " " + apiKey.Key - } else { - key = apiKey.Key - } - localVarHeaderParams["Authorization"] = key - } - } - } - req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles) - if err != nil { - return nil, err - } - - localVarHTTPResponse, err := a.client.callAPI(req) - if err != nil || localVarHTTPResponse == nil { - return localVarHTTPResponse, err - } - - localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) - localVarHTTPResponse.Body.Close() - localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) - if err != nil { - return localVarHTTPResponse, err - } - - if localVarHTTPResponse.StatusCode >= 300 { - newErr := &GenericOpenAPIError{ - body: localVarBody, - error: localVarHTTPResponse.Status, - } - return localVarHTTPResponse, newErr - } - - return localVarHTTPResponse, nil -} - -type ApiSetContainerRegistryRequest struct { - ctx context.Context - ApiService *ContainerRegistryAPIService - server string - containerRegistry *ContainerRegistry -} - -// Container Registry credentials to set -func (r ApiSetContainerRegistryRequest) ContainerRegistry(containerRegistry ContainerRegistry) ApiSetContainerRegistryRequest { - r.containerRegistry = &containerRegistry - return r -} - -func (r ApiSetContainerRegistryRequest) Execute() (*http.Response, error) { - return r.ApiService.SetContainerRegistryExecute(r) -} - -/* -SetContainerRegistry Set container registry credentials - -Set container registry credentials - - @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). - @param server Container Registry server name - @return ApiSetContainerRegistryRequest -*/ -func (a *ContainerRegistryAPIService) SetContainerRegistry(ctx context.Context, server string) ApiSetContainerRegistryRequest { - return ApiSetContainerRegistryRequest{ - ApiService: a, - ctx: ctx, - server: server, - } -} - -// Execute executes the request -func (a *ContainerRegistryAPIService) SetContainerRegistryExecute(r ApiSetContainerRegistryRequest) (*http.Response, error) { - var ( - localVarHTTPMethod = http.MethodPut - localVarPostBody interface{} - formFiles []formFile - ) - - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "ContainerRegistryAPIService.SetContainerRegistry") - if err != nil { - return nil, &GenericOpenAPIError{error: err.Error()} - } - - localVarPath := localBasePath + "/container-registry/{server}" - localVarPath = strings.Replace(localVarPath, "{"+"server"+"}", url.PathEscape(parameterValueToString(r.server, "server")), -1) - - localVarHeaderParams := make(map[string]string) - localVarQueryParams := url.Values{} - localVarFormParams := url.Values{} - if r.containerRegistry == nil { - return nil, reportError("containerRegistry is required and must be specified") - } - - // to determine the Content-Type header - localVarHTTPContentTypes := []string{} - - // set Content-Type header - localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes) - if localVarHTTPContentType != "" { - localVarHeaderParams["Content-Type"] = localVarHTTPContentType - } - - // to determine the Accept header - localVarHTTPHeaderAccepts := []string{} - - // set Accept header - localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) - if localVarHTTPHeaderAccept != "" { - localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept - } - // body params - localVarPostBody = r.containerRegistry - if r.ctx != nil { - // API Key Authentication - if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { - if apiKey, ok := auth["Bearer"]; ok { - var key string - if apiKey.Prefix != "" { - key = apiKey.Prefix + " " + apiKey.Key - } else { - key = apiKey.Key - } - localVarHeaderParams["Authorization"] = key - } - } - } - req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles) - if err != nil { - return nil, err - } - - localVarHTTPResponse, err := a.client.callAPI(req) - if err != nil || localVarHTTPResponse == nil { - return localVarHTTPResponse, err - } - - localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) - localVarHTTPResponse.Body.Close() - localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) - if err != nil { - return localVarHTTPResponse, err - } - - if localVarHTTPResponse.StatusCode >= 300 { - newErr := &GenericOpenAPIError{ - body: localVarBody, - error: localVarHTTPResponse.Status, - } - return localVarHTTPResponse, newErr - } - - return localVarHTTPResponse, nil -} diff --git a/pkg/apiclient/api_profile.go b/pkg/apiclient/api_env_var.go similarity index 72% rename from pkg/apiclient/api_profile.go rename to pkg/apiclient/api_env_var.go index 02a872a256..28c0266fc7 100644 --- a/pkg/apiclient/api_profile.go +++ b/pkg/apiclient/api_env_var.go @@ -16,49 +16,54 @@ import ( "io" "net/http" "net/url" + "strings" ) -// ProfileAPIService ProfileAPI service -type ProfileAPIService service +// EnvVarAPIService EnvVarAPI service +type EnvVarAPIService service -type ApiDeleteProfileDataRequest struct { +type ApiDeleteEnvironmentVariableRequest struct { ctx context.Context - ApiService *ProfileAPIService + ApiService *EnvVarAPIService + key string } -func (r ApiDeleteProfileDataRequest) Execute() (*http.Response, error) { - return r.ApiService.DeleteProfileDataExecute(r) +func (r ApiDeleteEnvironmentVariableRequest) Execute() (*http.Response, error) { + return r.ApiService.DeleteEnvironmentVariableExecute(r) } /* -DeleteProfileData Delete profile data +DeleteEnvironmentVariable Delete environment variable -Delete profile data +Delete environment variable @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). - @return ApiDeleteProfileDataRequest + @param key Environment Variable Key + @return ApiDeleteEnvironmentVariableRequest */ -func (a *ProfileAPIService) DeleteProfileData(ctx context.Context) ApiDeleteProfileDataRequest { - return ApiDeleteProfileDataRequest{ +func (a *EnvVarAPIService) DeleteEnvironmentVariable(ctx context.Context, key string) ApiDeleteEnvironmentVariableRequest { + return ApiDeleteEnvironmentVariableRequest{ ApiService: a, ctx: ctx, + key: key, } } // Execute executes the request -func (a *ProfileAPIService) DeleteProfileDataExecute(r ApiDeleteProfileDataRequest) (*http.Response, error) { +func (a *EnvVarAPIService) DeleteEnvironmentVariableExecute(r ApiDeleteEnvironmentVariableRequest) (*http.Response, error) { var ( localVarHTTPMethod = http.MethodDelete localVarPostBody interface{} formFiles []formFile ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "ProfileAPIService.DeleteProfileData") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "EnvVarAPIService.DeleteEnvironmentVariable") if err != nil { return nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/profile" + localVarPath := localBasePath + "/env/{key}" + localVarPath = strings.Replace(localVarPath, "{"+"key"+"}", url.PathEscape(parameterValueToString(r.key, "key")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -123,25 +128,25 @@ func (a *ProfileAPIService) DeleteProfileDataExecute(r ApiDeleteProfileDataReque return localVarHTTPResponse, nil } -type ApiGetProfileDataRequest struct { +type ApiListEnvironmentVariablesRequest struct { ctx context.Context - ApiService *ProfileAPIService + ApiService *EnvVarAPIService } -func (r ApiGetProfileDataRequest) Execute() (*ProfileData, *http.Response, error) { - return r.ApiService.GetProfileDataExecute(r) +func (r ApiListEnvironmentVariablesRequest) Execute() ([]EnvironmentVariable, *http.Response, error) { + return r.ApiService.ListEnvironmentVariablesExecute(r) } /* -GetProfileData Get profile data +ListEnvironmentVariables List environment variables -Get profile data +List environment variables @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). - @return ApiGetProfileDataRequest + @return ApiListEnvironmentVariablesRequest */ -func (a *ProfileAPIService) GetProfileData(ctx context.Context) ApiGetProfileDataRequest { - return ApiGetProfileDataRequest{ +func (a *EnvVarAPIService) ListEnvironmentVariables(ctx context.Context) ApiListEnvironmentVariablesRequest { + return ApiListEnvironmentVariablesRequest{ ApiService: a, ctx: ctx, } @@ -149,21 +154,21 @@ func (a *ProfileAPIService) GetProfileData(ctx context.Context) ApiGetProfileDat // Execute executes the request // -// @return ProfileData -func (a *ProfileAPIService) GetProfileDataExecute(r ApiGetProfileDataRequest) (*ProfileData, *http.Response, error) { +// @return []EnvironmentVariable +func (a *EnvVarAPIService) ListEnvironmentVariablesExecute(r ApiListEnvironmentVariablesRequest) ([]EnvironmentVariable, *http.Response, error) { var ( localVarHTTPMethod = http.MethodGet localVarPostBody interface{} formFiles []formFile - localVarReturnValue *ProfileData + localVarReturnValue []EnvironmentVariable ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "ProfileAPIService.GetProfileData") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "EnvVarAPIService.ListEnvironmentVariables") if err != nil { return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/profile" + localVarPath := localBasePath + "/env" localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -179,7 +184,7 @@ func (a *ProfileAPIService) GetProfileDataExecute(r ApiGetProfileDataRequest) (* } // to determine the Accept header - localVarHTTPHeaderAccepts := []string{"*/*"} + localVarHTTPHeaderAccepts := []string{"application/json"} // set Accept header localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) @@ -237,57 +242,57 @@ func (a *ProfileAPIService) GetProfileDataExecute(r ApiGetProfileDataRequest) (* return localVarReturnValue, localVarHTTPResponse, nil } -type ApiSetProfileDataRequest struct { - ctx context.Context - ApiService *ProfileAPIService - profileData *ProfileData +type ApiSaveEnvironmentVariableRequest struct { + ctx context.Context + ApiService *EnvVarAPIService + environmentVariable *EnvironmentVariable } -// Profile data -func (r ApiSetProfileDataRequest) ProfileData(profileData ProfileData) ApiSetProfileDataRequest { - r.profileData = &profileData +// Environment Variable +func (r ApiSaveEnvironmentVariableRequest) EnvironmentVariable(environmentVariable EnvironmentVariable) ApiSaveEnvironmentVariableRequest { + r.environmentVariable = &environmentVariable return r } -func (r ApiSetProfileDataRequest) Execute() (*http.Response, error) { - return r.ApiService.SetProfileDataExecute(r) +func (r ApiSaveEnvironmentVariableRequest) Execute() (*http.Response, error) { + return r.ApiService.SaveEnvironmentVariableExecute(r) } /* -SetProfileData Set profile data +SaveEnvironmentVariable Save environment variable -Set profile data +Save environment variable @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). - @return ApiSetProfileDataRequest + @return ApiSaveEnvironmentVariableRequest */ -func (a *ProfileAPIService) SetProfileData(ctx context.Context) ApiSetProfileDataRequest { - return ApiSetProfileDataRequest{ +func (a *EnvVarAPIService) SaveEnvironmentVariable(ctx context.Context) ApiSaveEnvironmentVariableRequest { + return ApiSaveEnvironmentVariableRequest{ ApiService: a, ctx: ctx, } } // Execute executes the request -func (a *ProfileAPIService) SetProfileDataExecute(r ApiSetProfileDataRequest) (*http.Response, error) { +func (a *EnvVarAPIService) SaveEnvironmentVariableExecute(r ApiSaveEnvironmentVariableRequest) (*http.Response, error) { var ( localVarHTTPMethod = http.MethodPut localVarPostBody interface{} formFiles []formFile ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "ProfileAPIService.SetProfileData") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "EnvVarAPIService.SaveEnvironmentVariable") if err != nil { return nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/profile" + localVarPath := localBasePath + "/env" localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} localVarFormParams := url.Values{} - if r.profileData == nil { - return nil, reportError("profileData is required and must be specified") + if r.environmentVariable == nil { + return nil, reportError("environmentVariable is required and must be specified") } // to determine the Content-Type header @@ -308,7 +313,7 @@ func (a *ProfileAPIService) SetProfileDataExecute(r ApiSetProfileDataRequest) (* localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept } // body params - localVarPostBody = r.profileData + localVarPostBody = r.environmentVariable if r.ctx != nil { // API Key Authentication if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { diff --git a/pkg/apiclient/api_git_provider.go b/pkg/apiclient/api_git_provider.go index aba377926a..518f7010fb 100644 --- a/pkg/apiclient/api_git_provider.go +++ b/pkg/apiclient/api_git_provider.go @@ -22,61 +22,52 @@ import ( // GitProviderAPIService GitProviderAPI service type GitProviderAPIService service -type ApiGetGitContextRequest struct { - ctx context.Context - ApiService *GitProviderAPIService - repository *GetRepositoryContext -} - -// Get repository context -func (r ApiGetGitContextRequest) Repository(repository GetRepositoryContext) ApiGetGitContextRequest { - r.repository = &repository - return r +type ApiDeleteGitProviderRequest struct { + ctx context.Context + ApiService *GitProviderAPIService + gitProviderId string } -func (r ApiGetGitContextRequest) Execute() (*GitRepository, *http.Response, error) { - return r.ApiService.GetGitContextExecute(r) +func (r ApiDeleteGitProviderRequest) Execute() (*http.Response, error) { + return r.ApiService.DeleteGitProviderExecute(r) } /* -GetGitContext Get Git context +DeleteGitProvider Delete Git provider -Get Git context +Delete Git provider @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). - @return ApiGetGitContextRequest + @param gitProviderId Git provider + @return ApiDeleteGitProviderRequest */ -func (a *GitProviderAPIService) GetGitContext(ctx context.Context) ApiGetGitContextRequest { - return ApiGetGitContextRequest{ - ApiService: a, - ctx: ctx, +func (a *GitProviderAPIService) DeleteGitProvider(ctx context.Context, gitProviderId string) ApiDeleteGitProviderRequest { + return ApiDeleteGitProviderRequest{ + ApiService: a, + ctx: ctx, + gitProviderId: gitProviderId, } } // Execute executes the request -// -// @return GitRepository -func (a *GitProviderAPIService) GetGitContextExecute(r ApiGetGitContextRequest) (*GitRepository, *http.Response, error) { +func (a *GitProviderAPIService) DeleteGitProviderExecute(r ApiDeleteGitProviderRequest) (*http.Response, error) { var ( - localVarHTTPMethod = http.MethodPost - localVarPostBody interface{} - formFiles []formFile - localVarReturnValue *GitRepository + localVarHTTPMethod = http.MethodDelete + localVarPostBody interface{} + formFiles []formFile ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "GitProviderAPIService.GetGitContext") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "GitProviderAPIService.DeleteGitProvider") if err != nil { - return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} + return nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/gitprovider/context" + localVarPath := localBasePath + "/gitprovider/{gitProviderId}" + localVarPath = strings.Replace(localVarPath, "{"+"gitProviderId"+"}", url.PathEscape(parameterValueToString(r.gitProviderId, "gitProviderId")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} localVarFormParams := url.Values{} - if r.repository == nil { - return localVarReturnValue, nil, reportError("repository is required and must be specified") - } // to determine the Content-Type header localVarHTTPContentTypes := []string{} @@ -88,15 +79,13 @@ func (a *GitProviderAPIService) GetGitContextExecute(r ApiGetGitContextRequest) } // to determine the Accept header - localVarHTTPHeaderAccepts := []string{"application/json"} + localVarHTTPHeaderAccepts := []string{} // set Accept header localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) if localVarHTTPHeaderAccept != "" { localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept } - // body params - localVarPostBody = r.repository if r.ctx != nil { // API Key Authentication if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { @@ -113,19 +102,19 @@ func (a *GitProviderAPIService) GetGitContextExecute(r ApiGetGitContextRequest) } req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles) if err != nil { - return localVarReturnValue, nil, err + return nil, err } localVarHTTPResponse, err := a.client.callAPI(req) if err != nil || localVarHTTPResponse == nil { - return localVarReturnValue, localVarHTTPResponse, err + return localVarHTTPResponse, err } localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) localVarHTTPResponse.Body.Close() localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) if err != nil { - return localVarReturnValue, localVarHTTPResponse, err + return localVarHTTPResponse, err } if localVarHTTPResponse.StatusCode >= 300 { @@ -133,42 +122,33 @@ func (a *GitProviderAPIService) GetGitContextExecute(r ApiGetGitContextRequest) body: localVarBody, error: localVarHTTPResponse.Status, } - return localVarReturnValue, localVarHTTPResponse, newErr - } - - err = a.client.decode(&localVarReturnValue, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) - if err != nil { - newErr := &GenericOpenAPIError{ - body: localVarBody, - error: err.Error(), - } - return localVarReturnValue, localVarHTTPResponse, newErr + return localVarHTTPResponse, newErr } - return localVarReturnValue, localVarHTTPResponse, nil + return localVarHTTPResponse, nil } -type ApiGetGitProviderRequest struct { +type ApiFindGitProviderRequest struct { ctx context.Context ApiService *GitProviderAPIService gitProviderId string } -func (r ApiGetGitProviderRequest) Execute() (*GitProvider, *http.Response, error) { - return r.ApiService.GetGitProviderExecute(r) +func (r ApiFindGitProviderRequest) Execute() (*GitProvider, *http.Response, error) { + return r.ApiService.FindGitProviderExecute(r) } /* -GetGitProvider Get Git provider +FindGitProvider Find Git provider -Get Git provider +Find Git provider @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @param gitProviderId ID - @return ApiGetGitProviderRequest + @return ApiFindGitProviderRequest */ -func (a *GitProviderAPIService) GetGitProvider(ctx context.Context, gitProviderId string) ApiGetGitProviderRequest { - return ApiGetGitProviderRequest{ +func (a *GitProviderAPIService) FindGitProvider(ctx context.Context, gitProviderId string) ApiFindGitProviderRequest { + return ApiFindGitProviderRequest{ ApiService: a, ctx: ctx, gitProviderId: gitProviderId, @@ -178,7 +158,7 @@ func (a *GitProviderAPIService) GetGitProvider(ctx context.Context, gitProviderI // Execute executes the request // // @return GitProvider -func (a *GitProviderAPIService) GetGitProviderExecute(r ApiGetGitProviderRequest) (*GitProvider, *http.Response, error) { +func (a *GitProviderAPIService) FindGitProviderExecute(r ApiFindGitProviderRequest) (*GitProvider, *http.Response, error) { var ( localVarHTTPMethod = http.MethodGet localVarPostBody interface{} @@ -186,7 +166,7 @@ func (a *GitProviderAPIService) GetGitProviderExecute(r ApiGetGitProviderRequest localVarReturnValue *GitProvider ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "GitProviderAPIService.GetGitProvider") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "GitProviderAPIService.FindGitProvider") if err != nil { return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } @@ -266,27 +246,27 @@ func (a *GitProviderAPIService) GetGitProviderExecute(r ApiGetGitProviderRequest return localVarReturnValue, localVarHTTPResponse, nil } -type ApiGetGitProviderIdForUrlRequest struct { +type ApiFindGitProviderIdForUrlRequest struct { ctx context.Context ApiService *GitProviderAPIService url string } -func (r ApiGetGitProviderIdForUrlRequest) Execute() (string, *http.Response, error) { - return r.ApiService.GetGitProviderIdForUrlExecute(r) +func (r ApiFindGitProviderIdForUrlRequest) Execute() (string, *http.Response, error) { + return r.ApiService.FindGitProviderIdForUrlExecute(r) } /* -GetGitProviderIdForUrl Get Git provider ID +FindGitProviderIdForUrl Find Git provider ID -Get Git provider ID +Find Git provider ID @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @param url Url - @return ApiGetGitProviderIdForUrlRequest + @return ApiFindGitProviderIdForUrlRequest */ -func (a *GitProviderAPIService) GetGitProviderIdForUrl(ctx context.Context, url string) ApiGetGitProviderIdForUrlRequest { - return ApiGetGitProviderIdForUrlRequest{ +func (a *GitProviderAPIService) FindGitProviderIdForUrl(ctx context.Context, url string) ApiFindGitProviderIdForUrlRequest { + return ApiFindGitProviderIdForUrlRequest{ ApiService: a, ctx: ctx, url: url, @@ -296,7 +276,7 @@ func (a *GitProviderAPIService) GetGitProviderIdForUrl(ctx context.Context, url // Execute executes the request // // @return string -func (a *GitProviderAPIService) GetGitProviderIdForUrlExecute(r ApiGetGitProviderIdForUrlRequest) (string, *http.Response, error) { +func (a *GitProviderAPIService) FindGitProviderIdForUrlExecute(r ApiFindGitProviderIdForUrlRequest) (string, *http.Response, error) { var ( localVarHTTPMethod = http.MethodGet localVarPostBody interface{} @@ -304,7 +284,7 @@ func (a *GitProviderAPIService) GetGitProviderIdForUrlExecute(r ApiGetGitProvide localVarReturnValue string ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "GitProviderAPIService.GetGitProviderIdForUrl") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "GitProviderAPIService.FindGitProviderIdForUrl") if err != nil { return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } @@ -384,6 +364,132 @@ func (a *GitProviderAPIService) GetGitProviderIdForUrlExecute(r ApiGetGitProvide return localVarReturnValue, localVarHTTPResponse, nil } +type ApiGetGitContextRequest struct { + ctx context.Context + ApiService *GitProviderAPIService + repository *GetRepositoryContext +} + +// Get repository context +func (r ApiGetGitContextRequest) Repository(repository GetRepositoryContext) ApiGetGitContextRequest { + r.repository = &repository + return r +} + +func (r ApiGetGitContextRequest) Execute() (*GitRepository, *http.Response, error) { + return r.ApiService.GetGitContextExecute(r) +} + +/* +GetGitContext Get Git context + +Get Git context + + @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + @return ApiGetGitContextRequest +*/ +func (a *GitProviderAPIService) GetGitContext(ctx context.Context) ApiGetGitContextRequest { + return ApiGetGitContextRequest{ + ApiService: a, + ctx: ctx, + } +} + +// Execute executes the request +// +// @return GitRepository +func (a *GitProviderAPIService) GetGitContextExecute(r ApiGetGitContextRequest) (*GitRepository, *http.Response, error) { + var ( + localVarHTTPMethod = http.MethodPost + localVarPostBody interface{} + formFiles []formFile + localVarReturnValue *GitRepository + ) + + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "GitProviderAPIService.GetGitContext") + if err != nil { + return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} + } + + localVarPath := localBasePath + "/gitprovider/context" + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + if r.repository == nil { + return localVarReturnValue, nil, reportError("repository is required and must be specified") + } + + // to determine the Content-Type header + localVarHTTPContentTypes := []string{} + + // set Content-Type header + localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes) + if localVarHTTPContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHTTPContentType + } + + // to determine the Accept header + localVarHTTPHeaderAccepts := []string{"application/json"} + + // set Accept header + localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) + if localVarHTTPHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept + } + // body params + localVarPostBody = r.repository + if r.ctx != nil { + // API Key Authentication + if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { + if apiKey, ok := auth["Bearer"]; ok { + var key string + if apiKey.Prefix != "" { + key = apiKey.Prefix + " " + apiKey.Key + } else { + key = apiKey.Key + } + localVarHeaderParams["Authorization"] = key + } + } + } + req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHTTPResponse, err := a.client.callAPI(req) + if err != nil || localVarHTTPResponse == nil { + return localVarReturnValue, localVarHTTPResponse, err + } + + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) + localVarHTTPResponse.Body.Close() + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) + if err != nil { + return localVarReturnValue, localVarHTTPResponse, err + } + + if localVarHTTPResponse.StatusCode >= 300 { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: localVarHTTPResponse.Status, + } + return localVarReturnValue, localVarHTTPResponse, newErr + } + + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: err.Error(), + } + return localVarReturnValue, localVarHTTPResponse, newErr + } + + return localVarReturnValue, localVarHTTPResponse, nil +} + type ApiGetGitUserRequest struct { ctx context.Context ApiService *GitProviderAPIService @@ -1432,152 +1538,46 @@ func (a *GitProviderAPIService) ListGitProvidersForUrlExecute(r ApiListGitProvid return localVarReturnValue, localVarHTTPResponse, nil } -type ApiRemoveGitProviderRequest struct { - ctx context.Context - ApiService *GitProviderAPIService - gitProviderId string -} - -func (r ApiRemoveGitProviderRequest) Execute() (*http.Response, error) { - return r.ApiService.RemoveGitProviderExecute(r) -} - -/* -RemoveGitProvider Remove Git provider - -Remove Git provider - - @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). - @param gitProviderId Git provider - @return ApiRemoveGitProviderRequest -*/ -func (a *GitProviderAPIService) RemoveGitProvider(ctx context.Context, gitProviderId string) ApiRemoveGitProviderRequest { - return ApiRemoveGitProviderRequest{ - ApiService: a, - ctx: ctx, - gitProviderId: gitProviderId, - } -} - -// Execute executes the request -func (a *GitProviderAPIService) RemoveGitProviderExecute(r ApiRemoveGitProviderRequest) (*http.Response, error) { - var ( - localVarHTTPMethod = http.MethodDelete - localVarPostBody interface{} - formFiles []formFile - ) - - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "GitProviderAPIService.RemoveGitProvider") - if err != nil { - return nil, &GenericOpenAPIError{error: err.Error()} - } - - localVarPath := localBasePath + "/gitprovider/{gitProviderId}" - localVarPath = strings.Replace(localVarPath, "{"+"gitProviderId"+"}", url.PathEscape(parameterValueToString(r.gitProviderId, "gitProviderId")), -1) - - localVarHeaderParams := make(map[string]string) - localVarQueryParams := url.Values{} - localVarFormParams := url.Values{} - - // to determine the Content-Type header - localVarHTTPContentTypes := []string{} - - // set Content-Type header - localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes) - if localVarHTTPContentType != "" { - localVarHeaderParams["Content-Type"] = localVarHTTPContentType - } - - // to determine the Accept header - localVarHTTPHeaderAccepts := []string{} - - // set Accept header - localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) - if localVarHTTPHeaderAccept != "" { - localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept - } - if r.ctx != nil { - // API Key Authentication - if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { - if apiKey, ok := auth["Bearer"]; ok { - var key string - if apiKey.Prefix != "" { - key = apiKey.Prefix + " " + apiKey.Key - } else { - key = apiKey.Key - } - localVarHeaderParams["Authorization"] = key - } - } - } - req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles) - if err != nil { - return nil, err - } - - localVarHTTPResponse, err := a.client.callAPI(req) - if err != nil || localVarHTTPResponse == nil { - return localVarHTTPResponse, err - } - - localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) - localVarHTTPResponse.Body.Close() - localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) - if err != nil { - return localVarHTTPResponse, err - } - - if localVarHTTPResponse.StatusCode >= 300 { - newErr := &GenericOpenAPIError{ - body: localVarBody, - error: localVarHTTPResponse.Status, - } - return localVarHTTPResponse, newErr - } - - return localVarHTTPResponse, nil -} - -type ApiSetGitProviderRequest struct { +type ApiSaveGitProviderRequest struct { ctx context.Context ApiService *GitProviderAPIService gitProviderConfig *SetGitProviderConfig } // Git provider -func (r ApiSetGitProviderRequest) GitProviderConfig(gitProviderConfig SetGitProviderConfig) ApiSetGitProviderRequest { +func (r ApiSaveGitProviderRequest) GitProviderConfig(gitProviderConfig SetGitProviderConfig) ApiSaveGitProviderRequest { r.gitProviderConfig = &gitProviderConfig return r } -func (r ApiSetGitProviderRequest) Execute() (*http.Response, error) { - return r.ApiService.SetGitProviderExecute(r) +func (r ApiSaveGitProviderRequest) Execute() (*http.Response, error) { + return r.ApiService.SaveGitProviderExecute(r) } /* -SetGitProvider Set Git provider +SaveGitProvider Save Git provider -Set Git provider +Save Git provider @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). - @return ApiSetGitProviderRequest + @return ApiSaveGitProviderRequest */ -func (a *GitProviderAPIService) SetGitProvider(ctx context.Context) ApiSetGitProviderRequest { - return ApiSetGitProviderRequest{ +func (a *GitProviderAPIService) SaveGitProvider(ctx context.Context) ApiSaveGitProviderRequest { + return ApiSaveGitProviderRequest{ ApiService: a, ctx: ctx, } } // Execute executes the request -func (a *GitProviderAPIService) SetGitProviderExecute(r ApiSetGitProviderRequest) (*http.Response, error) { +func (a *GitProviderAPIService) SaveGitProviderExecute(r ApiSaveGitProviderRequest) (*http.Response, error) { var ( localVarHTTPMethod = http.MethodPut localVarPostBody interface{} formFiles []formFile ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "GitProviderAPIService.SetGitProvider") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "GitProviderAPIService.SaveGitProvider") if err != nil { return nil, &GenericOpenAPIError{error: err.Error()} } diff --git a/pkg/apiclient/api_job.go b/pkg/apiclient/api_job.go new file mode 100644 index 0000000000..dfc2b0652e --- /dev/null +++ b/pkg/apiclient/api_job.go @@ -0,0 +1,193 @@ +/* +Daytona Server API + +Daytona Server API + +API version: v0.0.0-dev +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package apiclient + +import ( + "bytes" + "context" + "io" + "net/http" + "net/url" + "reflect" +) + +// JobAPIService JobAPI service +type JobAPIService service + +type ApiListJobsRequest struct { + ctx context.Context + ApiService *JobAPIService + states *[]string + actions *[]string + resourceId *string + resourceType *string +} + +// Job States +func (r ApiListJobsRequest) States(states []string) ApiListJobsRequest { + r.states = &states + return r +} + +// Job Actions +func (r ApiListJobsRequest) Actions(actions []string) ApiListJobsRequest { + r.actions = &actions + return r +} + +// Resource ID +func (r ApiListJobsRequest) ResourceId(resourceId string) ApiListJobsRequest { + r.resourceId = &resourceId + return r +} + +// Resource Type +func (r ApiListJobsRequest) ResourceType(resourceType string) ApiListJobsRequest { + r.resourceType = &resourceType + return r +} + +func (r ApiListJobsRequest) Execute() ([]Job, *http.Response, error) { + return r.ApiService.ListJobsExecute(r) +} + +/* +ListJobs List jobs + +List jobs + + @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + @return ApiListJobsRequest +*/ +func (a *JobAPIService) ListJobs(ctx context.Context) ApiListJobsRequest { + return ApiListJobsRequest{ + ApiService: a, + ctx: ctx, + } +} + +// Execute executes the request +// +// @return []Job +func (a *JobAPIService) ListJobsExecute(r ApiListJobsRequest) ([]Job, *http.Response, error) { + var ( + localVarHTTPMethod = http.MethodGet + localVarPostBody interface{} + formFiles []formFile + localVarReturnValue []Job + ) + + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "JobAPIService.ListJobs") + if err != nil { + return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} + } + + localVarPath := localBasePath + "/job" + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + if r.states != nil { + t := *r.states + if reflect.TypeOf(t).Kind() == reflect.Slice { + s := reflect.ValueOf(t) + for i := 0; i < s.Len(); i++ { + parameterAddToHeaderOrQuery(localVarQueryParams, "states", s.Index(i).Interface(), "multi") + } + } else { + parameterAddToHeaderOrQuery(localVarQueryParams, "states", t, "multi") + } + } + if r.actions != nil { + t := *r.actions + if reflect.TypeOf(t).Kind() == reflect.Slice { + s := reflect.ValueOf(t) + for i := 0; i < s.Len(); i++ { + parameterAddToHeaderOrQuery(localVarQueryParams, "actions", s.Index(i).Interface(), "multi") + } + } else { + parameterAddToHeaderOrQuery(localVarQueryParams, "actions", t, "multi") + } + } + if r.resourceId != nil { + parameterAddToHeaderOrQuery(localVarQueryParams, "resourceId", r.resourceId, "") + } + if r.resourceType != nil { + parameterAddToHeaderOrQuery(localVarQueryParams, "resourceType", r.resourceType, "") + } + // to determine the Content-Type header + localVarHTTPContentTypes := []string{} + + // set Content-Type header + localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes) + if localVarHTTPContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHTTPContentType + } + + // to determine the Accept header + localVarHTTPHeaderAccepts := []string{"application/json"} + + // set Accept header + localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) + if localVarHTTPHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept + } + if r.ctx != nil { + // API Key Authentication + if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { + if apiKey, ok := auth["Bearer"]; ok { + var key string + if apiKey.Prefix != "" { + key = apiKey.Prefix + " " + apiKey.Key + } else { + key = apiKey.Key + } + localVarHeaderParams["Authorization"] = key + } + } + } + req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHTTPResponse, err := a.client.callAPI(req) + if err != nil || localVarHTTPResponse == nil { + return localVarReturnValue, localVarHTTPResponse, err + } + + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) + localVarHTTPResponse.Body.Close() + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) + if err != nil { + return localVarReturnValue, localVarHTTPResponse, err + } + + if localVarHTTPResponse.StatusCode >= 300 { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: localVarHTTPResponse.Status, + } + return localVarReturnValue, localVarHTTPResponse, newErr + } + + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: err.Error(), + } + return localVarReturnValue, localVarHTTPResponse, newErr + } + + return localVarReturnValue, localVarHTTPResponse, nil +} diff --git a/pkg/apiclient/api_prebuild.go b/pkg/apiclient/api_prebuild.go index 388f9078cb..f76b593d4f 100644 --- a/pkg/apiclient/api_prebuild.go +++ b/pkg/apiclient/api_prebuild.go @@ -23,11 +23,11 @@ import ( type PrebuildAPIService service type ApiDeletePrebuildRequest struct { - ctx context.Context - ApiService *PrebuildAPIService - configName string - prebuildId string - force *bool + ctx context.Context + ApiService *PrebuildAPIService + templateName string + prebuildId string + force *bool } // Force @@ -46,16 +46,16 @@ DeletePrebuild Delete prebuild Delete prebuild @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). - @param configName Project config name + @param templateName Workspace template name @param prebuildId Prebuild ID @return ApiDeletePrebuildRequest */ -func (a *PrebuildAPIService) DeletePrebuild(ctx context.Context, configName string, prebuildId string) ApiDeletePrebuildRequest { +func (a *PrebuildAPIService) DeletePrebuild(ctx context.Context, templateName string, prebuildId string) ApiDeletePrebuildRequest { return ApiDeletePrebuildRequest{ - ApiService: a, - ctx: ctx, - configName: configName, - prebuildId: prebuildId, + ApiService: a, + ctx: ctx, + templateName: templateName, + prebuildId: prebuildId, } } @@ -72,8 +72,8 @@ func (a *PrebuildAPIService) DeletePrebuildExecute(r ApiDeletePrebuildRequest) ( return nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/project-config/{configName}/prebuild/{prebuildId}" - localVarPath = strings.Replace(localVarPath, "{"+"configName"+"}", url.PathEscape(parameterValueToString(r.configName, "configName")), -1) + localVarPath := localBasePath + "/workspace-template/{templateName}/prebuild/{prebuildId}" + localVarPath = strings.Replace(localVarPath, "{"+"templateName"+"}", url.PathEscape(parameterValueToString(r.templateName, "templateName")), -1) localVarPath = strings.Replace(localVarPath, "{"+"prebuildId"+"}", url.PathEscape(parameterValueToString(r.prebuildId, "prebuildId")), -1) localVarHeaderParams := make(map[string]string) @@ -142,40 +142,40 @@ func (a *PrebuildAPIService) DeletePrebuildExecute(r ApiDeletePrebuildRequest) ( return localVarHTTPResponse, nil } -type ApiGetPrebuildRequest struct { - ctx context.Context - ApiService *PrebuildAPIService - configName string - prebuildId string +type ApiFindPrebuildRequest struct { + ctx context.Context + ApiService *PrebuildAPIService + templateName string + prebuildId string } -func (r ApiGetPrebuildRequest) Execute() (*PrebuildDTO, *http.Response, error) { - return r.ApiService.GetPrebuildExecute(r) +func (r ApiFindPrebuildRequest) Execute() (*PrebuildDTO, *http.Response, error) { + return r.ApiService.FindPrebuildExecute(r) } /* -GetPrebuild Get prebuild +FindPrebuild Find prebuild -Get prebuild +Find prebuild @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). - @param configName Project config name + @param templateName Workspace template name @param prebuildId Prebuild ID - @return ApiGetPrebuildRequest + @return ApiFindPrebuildRequest */ -func (a *PrebuildAPIService) GetPrebuild(ctx context.Context, configName string, prebuildId string) ApiGetPrebuildRequest { - return ApiGetPrebuildRequest{ - ApiService: a, - ctx: ctx, - configName: configName, - prebuildId: prebuildId, +func (a *PrebuildAPIService) FindPrebuild(ctx context.Context, templateName string, prebuildId string) ApiFindPrebuildRequest { + return ApiFindPrebuildRequest{ + ApiService: a, + ctx: ctx, + templateName: templateName, + prebuildId: prebuildId, } } // Execute executes the request // // @return PrebuildDTO -func (a *PrebuildAPIService) GetPrebuildExecute(r ApiGetPrebuildRequest) (*PrebuildDTO, *http.Response, error) { +func (a *PrebuildAPIService) FindPrebuildExecute(r ApiFindPrebuildRequest) (*PrebuildDTO, *http.Response, error) { var ( localVarHTTPMethod = http.MethodGet localVarPostBody interface{} @@ -183,13 +183,13 @@ func (a *PrebuildAPIService) GetPrebuildExecute(r ApiGetPrebuildRequest) (*Prebu localVarReturnValue *PrebuildDTO ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "PrebuildAPIService.GetPrebuild") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "PrebuildAPIService.FindPrebuild") if err != nil { return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/project-config/{configName}/prebuild/{prebuildId}" - localVarPath = strings.Replace(localVarPath, "{"+"configName"+"}", url.PathEscape(parameterValueToString(r.configName, "configName")), -1) + localVarPath := localBasePath + "/workspace-template/{templateName}/prebuild/{prebuildId}" + localVarPath = strings.Replace(localVarPath, "{"+"templateName"+"}", url.PathEscape(parameterValueToString(r.templateName, "templateName")), -1) localVarPath = strings.Replace(localVarPath, "{"+"prebuildId"+"}", url.PathEscape(parameterValueToString(r.prebuildId, "prebuildId")), -1) localVarHeaderParams := make(map[string]string) @@ -304,7 +304,7 @@ func (a *PrebuildAPIService) ListPrebuildsExecute(r ApiListPrebuildsRequest) ([] return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/project-config/prebuild" + localVarPath := localBasePath + "/workspace-template/prebuild" localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -378,37 +378,37 @@ func (a *PrebuildAPIService) ListPrebuildsExecute(r ApiListPrebuildsRequest) ([] return localVarReturnValue, localVarHTTPResponse, nil } -type ApiListPrebuildsForProjectConfigRequest struct { - ctx context.Context - ApiService *PrebuildAPIService - configName string +type ApiListPrebuildsForWorkspaceTemplateRequest struct { + ctx context.Context + ApiService *PrebuildAPIService + templateName string } -func (r ApiListPrebuildsForProjectConfigRequest) Execute() ([]PrebuildDTO, *http.Response, error) { - return r.ApiService.ListPrebuildsForProjectConfigExecute(r) +func (r ApiListPrebuildsForWorkspaceTemplateRequest) Execute() ([]PrebuildDTO, *http.Response, error) { + return r.ApiService.ListPrebuildsForWorkspaceTemplateExecute(r) } /* -ListPrebuildsForProjectConfig List prebuilds for project config +ListPrebuildsForWorkspaceTemplate List prebuilds for workspace template -List prebuilds for project config +List prebuilds for workspace template @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). - @param configName Config name - @return ApiListPrebuildsForProjectConfigRequest + @param templateName Template name + @return ApiListPrebuildsForWorkspaceTemplateRequest */ -func (a *PrebuildAPIService) ListPrebuildsForProjectConfig(ctx context.Context, configName string) ApiListPrebuildsForProjectConfigRequest { - return ApiListPrebuildsForProjectConfigRequest{ - ApiService: a, - ctx: ctx, - configName: configName, +func (a *PrebuildAPIService) ListPrebuildsForWorkspaceTemplate(ctx context.Context, templateName string) ApiListPrebuildsForWorkspaceTemplateRequest { + return ApiListPrebuildsForWorkspaceTemplateRequest{ + ApiService: a, + ctx: ctx, + templateName: templateName, } } // Execute executes the request // // @return []PrebuildDTO -func (a *PrebuildAPIService) ListPrebuildsForProjectConfigExecute(r ApiListPrebuildsForProjectConfigRequest) ([]PrebuildDTO, *http.Response, error) { +func (a *PrebuildAPIService) ListPrebuildsForWorkspaceTemplateExecute(r ApiListPrebuildsForWorkspaceTemplateRequest) ([]PrebuildDTO, *http.Response, error) { var ( localVarHTTPMethod = http.MethodGet localVarPostBody interface{} @@ -416,13 +416,13 @@ func (a *PrebuildAPIService) ListPrebuildsForProjectConfigExecute(r ApiListPrebu localVarReturnValue []PrebuildDTO ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "PrebuildAPIService.ListPrebuildsForProjectConfig") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "PrebuildAPIService.ListPrebuildsForWorkspaceTemplate") if err != nil { return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/project-config/{configName}/prebuild" - localVarPath = strings.Replace(localVarPath, "{"+"configName"+"}", url.PathEscape(parameterValueToString(r.configName, "configName")), -1) + localVarPath := localBasePath + "/workspace-template/{templateName}/prebuild" + localVarPath = strings.Replace(localVarPath, "{"+"templateName"+"}", url.PathEscape(parameterValueToString(r.templateName, "templateName")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -499,12 +499,12 @@ func (a *PrebuildAPIService) ListPrebuildsForProjectConfigExecute(r ApiListPrebu type ApiProcessGitEventRequest struct { ctx context.Context ApiService *PrebuildAPIService - workspace *map[string]interface{} + body *map[string]interface{} } // Webhook event -func (r ApiProcessGitEventRequest) Workspace(workspace map[string]interface{}) ApiProcessGitEventRequest { - r.workspace = &workspace +func (r ApiProcessGitEventRequest) Body(body map[string]interface{}) ApiProcessGitEventRequest { + r.body = &body return r } @@ -540,13 +540,13 @@ func (a *PrebuildAPIService) ProcessGitEventExecute(r ApiProcessGitEventRequest) return nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/project-config/prebuild/process-git-event" + localVarPath := localBasePath + "/workspace-template/prebuild/process-git-event" localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} localVarFormParams := url.Values{} - if r.workspace == nil { - return nil, reportError("workspace is required and must be specified") + if r.body == nil { + return nil, reportError("body is required and must be specified") } // to determine the Content-Type header @@ -567,7 +567,7 @@ func (a *PrebuildAPIService) ProcessGitEventExecute(r ApiProcessGitEventRequest) localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept } // body params - localVarPostBody = r.workspace + localVarPostBody = r.body if r.ctx != nil { // API Key Authentication if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { @@ -610,44 +610,44 @@ func (a *PrebuildAPIService) ProcessGitEventExecute(r ApiProcessGitEventRequest) return localVarHTTPResponse, nil } -type ApiSetPrebuildRequest struct { - ctx context.Context - ApiService *PrebuildAPIService - configName string - prebuild *CreatePrebuildDTO +type ApiSavePrebuildRequest struct { + ctx context.Context + ApiService *PrebuildAPIService + templateName string + prebuild *CreatePrebuildDTO } // Prebuild -func (r ApiSetPrebuildRequest) Prebuild(prebuild CreatePrebuildDTO) ApiSetPrebuildRequest { +func (r ApiSavePrebuildRequest) Prebuild(prebuild CreatePrebuildDTO) ApiSavePrebuildRequest { r.prebuild = &prebuild return r } -func (r ApiSetPrebuildRequest) Execute() (string, *http.Response, error) { - return r.ApiService.SetPrebuildExecute(r) +func (r ApiSavePrebuildRequest) Execute() (string, *http.Response, error) { + return r.ApiService.SavePrebuildExecute(r) } /* -SetPrebuild Set prebuild +SavePrebuild Save prebuild -Set prebuild +Save prebuild @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). - @param configName Config name - @return ApiSetPrebuildRequest + @param templateName Template name + @return ApiSavePrebuildRequest */ -func (a *PrebuildAPIService) SetPrebuild(ctx context.Context, configName string) ApiSetPrebuildRequest { - return ApiSetPrebuildRequest{ - ApiService: a, - ctx: ctx, - configName: configName, +func (a *PrebuildAPIService) SavePrebuild(ctx context.Context, templateName string) ApiSavePrebuildRequest { + return ApiSavePrebuildRequest{ + ApiService: a, + ctx: ctx, + templateName: templateName, } } // Execute executes the request // // @return string -func (a *PrebuildAPIService) SetPrebuildExecute(r ApiSetPrebuildRequest) (string, *http.Response, error) { +func (a *PrebuildAPIService) SavePrebuildExecute(r ApiSavePrebuildRequest) (string, *http.Response, error) { var ( localVarHTTPMethod = http.MethodPut localVarPostBody interface{} @@ -655,13 +655,13 @@ func (a *PrebuildAPIService) SetPrebuildExecute(r ApiSetPrebuildRequest) (string localVarReturnValue string ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "PrebuildAPIService.SetPrebuild") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "PrebuildAPIService.SavePrebuild") if err != nil { return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/project-config/{configName}/prebuild" - localVarPath = strings.Replace(localVarPath, "{"+"configName"+"}", url.PathEscape(parameterValueToString(r.configName, "configName")), -1) + localVarPath := localBasePath + "/workspace-template/{templateName}/prebuild" + localVarPath = strings.Replace(localVarPath, "{"+"templateName"+"}", url.PathEscape(parameterValueToString(r.templateName, "templateName")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} diff --git a/pkg/apiclient/api_provider.go b/pkg/apiclient/api_provider.go index f30b122ffd..7944417e9f 100644 --- a/pkg/apiclient/api_provider.go +++ b/pkg/apiclient/api_provider.go @@ -22,51 +22,51 @@ import ( // ProviderAPIService ProviderAPI service type ProviderAPIService service -type ApiGetTargetManifestRequest struct { +type ApiGetRunnerProvidersRequest struct { ctx context.Context ApiService *ProviderAPIService - provider string + runnerId string } -func (r ApiGetTargetManifestRequest) Execute() (*map[string]ProviderProviderTargetProperty, *http.Response, error) { - return r.ApiService.GetTargetManifestExecute(r) +func (r ApiGetRunnerProvidersRequest) Execute() ([]ProviderInfo, *http.Response, error) { + return r.ApiService.GetRunnerProvidersExecute(r) } /* -GetTargetManifest Get provider target manifest +GetRunnerProviders Get runner providers -Get provider target manifest +Get runner providers @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). - @param provider Provider name - @return ApiGetTargetManifestRequest + @param runnerId Runner ID + @return ApiGetRunnerProvidersRequest */ -func (a *ProviderAPIService) GetTargetManifest(ctx context.Context, provider string) ApiGetTargetManifestRequest { - return ApiGetTargetManifestRequest{ +func (a *ProviderAPIService) GetRunnerProviders(ctx context.Context, runnerId string) ApiGetRunnerProvidersRequest { + return ApiGetRunnerProvidersRequest{ ApiService: a, ctx: ctx, - provider: provider, + runnerId: runnerId, } } // Execute executes the request // -// @return map[string]ProviderProviderTargetProperty -func (a *ProviderAPIService) GetTargetManifestExecute(r ApiGetTargetManifestRequest) (*map[string]ProviderProviderTargetProperty, *http.Response, error) { +// @return []ProviderInfo +func (a *ProviderAPIService) GetRunnerProvidersExecute(r ApiGetRunnerProvidersRequest) ([]ProviderInfo, *http.Response, error) { var ( localVarHTTPMethod = http.MethodGet localVarPostBody interface{} formFiles []formFile - localVarReturnValue *map[string]ProviderProviderTargetProperty + localVarReturnValue []ProviderInfo ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "ProviderAPIService.GetTargetManifest") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "ProviderAPIService.GetRunnerProviders") if err != nil { return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/provider/{provider}/target-manifest" - localVarPath = strings.Replace(localVarPath, "{"+"provider"+"}", url.PathEscape(parameterValueToString(r.provider, "provider")), -1) + localVarPath := localBasePath + "/runner/{runnerId}/provider" + localVarPath = strings.Replace(localVarPath, "{"+"runnerId"+"}", url.PathEscape(parameterValueToString(r.runnerId, "runnerId")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -82,7 +82,7 @@ func (a *ProviderAPIService) GetTargetManifestExecute(r ApiGetTargetManifestRequ } // to determine the Accept header - localVarHTTPHeaderAccepts := []string{"*/*"} + localVarHTTPHeaderAccepts := []string{"application/json"} // set Accept header localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) @@ -141,14 +141,16 @@ func (a *ProviderAPIService) GetTargetManifestExecute(r ApiGetTargetManifestRequ } type ApiInstallProviderRequest struct { - ctx context.Context - ApiService *ProviderAPIService - provider *InstallProviderRequest + ctx context.Context + ApiService *ProviderAPIService + runnerId string + providerName string + providerVersion *string } -// Provider to install -func (r ApiInstallProviderRequest) Provider(provider InstallProviderRequest) ApiInstallProviderRequest { - r.provider = &provider +// Provider version - defaults to 'latest' +func (r ApiInstallProviderRequest) ProviderVersion(providerVersion string) ApiInstallProviderRequest { + r.providerVersion = &providerVersion return r } @@ -157,17 +159,21 @@ func (r ApiInstallProviderRequest) Execute() (*http.Response, error) { } /* -InstallProvider Install a provider +InstallProvider Install provider -Install a provider +Install provider @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + @param runnerId Runner ID + @param providerName Provider name @return ApiInstallProviderRequest */ -func (a *ProviderAPIService) InstallProvider(ctx context.Context) ApiInstallProviderRequest { +func (a *ProviderAPIService) InstallProvider(ctx context.Context, runnerId string, providerName string) ApiInstallProviderRequest { return ApiInstallProviderRequest{ - ApiService: a, - ctx: ctx, + ApiService: a, + ctx: ctx, + runnerId: runnerId, + providerName: providerName, } } @@ -184,17 +190,19 @@ func (a *ProviderAPIService) InstallProviderExecute(r ApiInstallProviderRequest) return nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/provider/install" + localVarPath := localBasePath + "/runner/{runnerId}/provider/{providerName}/install" + localVarPath = strings.Replace(localVarPath, "{"+"runnerId"+"}", url.PathEscape(parameterValueToString(r.runnerId, "runnerId")), -1) + localVarPath = strings.Replace(localVarPath, "{"+"providerName"+"}", url.PathEscape(parameterValueToString(r.providerName, "providerName")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} localVarFormParams := url.Values{} - if r.provider == nil { - return nil, reportError("provider is required and must be specified") - } + if r.providerVersion != nil { + parameterAddToHeaderOrQuery(localVarQueryParams, "providerVersion", r.providerVersion, "") + } // to determine the Content-Type header - localVarHTTPContentTypes := []string{"application/json"} + localVarHTTPContentTypes := []string{} // set Content-Type header localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes) @@ -210,8 +218,6 @@ func (a *ProviderAPIService) InstallProviderExecute(r ApiInstallProviderRequest) if localVarHTTPHeaderAccept != "" { localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept } - // body params - localVarPostBody = r.provider if r.ctx != nil { // API Key Authentication if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { @@ -257,9 +263,16 @@ func (a *ProviderAPIService) InstallProviderExecute(r ApiInstallProviderRequest) type ApiListProvidersRequest struct { ctx context.Context ApiService *ProviderAPIService + runnerId *string +} + +// Runner ID +func (r ApiListProvidersRequest) RunnerId(runnerId string) ApiListProvidersRequest { + r.runnerId = &runnerId + return r } -func (r ApiListProvidersRequest) Execute() ([]Provider, *http.Response, error) { +func (r ApiListProvidersRequest) Execute() ([]ProviderInfo, *http.Response, error) { return r.ApiService.ListProvidersExecute(r) } @@ -280,13 +293,13 @@ func (a *ProviderAPIService) ListProviders(ctx context.Context) ApiListProviders // Execute executes the request // -// @return []Provider -func (a *ProviderAPIService) ListProvidersExecute(r ApiListProvidersRequest) ([]Provider, *http.Response, error) { +// @return []ProviderInfo +func (a *ProviderAPIService) ListProvidersExecute(r ApiListProvidersRequest) ([]ProviderInfo, *http.Response, error) { var ( localVarHTTPMethod = http.MethodGet localVarPostBody interface{} formFiles []formFile - localVarReturnValue []Provider + localVarReturnValue []ProviderInfo ) localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "ProviderAPIService.ListProviders") @@ -294,12 +307,15 @@ func (a *ProviderAPIService) ListProvidersExecute(r ApiListProvidersRequest) ([] return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/provider" + localVarPath := localBasePath + "/runner/provider" localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} localVarFormParams := url.Values{} + if r.runnerId != nil { + parameterAddToHeaderOrQuery(localVarQueryParams, "runnerId", r.runnerId, "") + } // to determine the Content-Type header localVarHTTPContentTypes := []string{} @@ -368,10 +384,125 @@ func (a *ProviderAPIService) ListProvidersExecute(r ApiListProvidersRequest) ([] return localVarReturnValue, localVarHTTPResponse, nil } -type ApiUninstallProviderRequest struct { +type ApiListProvidersForInstallRequest struct { ctx context.Context ApiService *ProviderAPIService - provider string +} + +func (r ApiListProvidersForInstallRequest) Execute() ([]ProviderDTO, *http.Response, error) { + return r.ApiService.ListProvidersForInstallExecute(r) +} + +/* +ListProvidersForInstall List providers available for installation + +List providers available for installation + + @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + @return ApiListProvidersForInstallRequest +*/ +func (a *ProviderAPIService) ListProvidersForInstall(ctx context.Context) ApiListProvidersForInstallRequest { + return ApiListProvidersForInstallRequest{ + ApiService: a, + ctx: ctx, + } +} + +// Execute executes the request +// +// @return []ProviderDTO +func (a *ProviderAPIService) ListProvidersForInstallExecute(r ApiListProvidersForInstallRequest) ([]ProviderDTO, *http.Response, error) { + var ( + localVarHTTPMethod = http.MethodGet + localVarPostBody interface{} + formFiles []formFile + localVarReturnValue []ProviderDTO + ) + + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "ProviderAPIService.ListProvidersForInstall") + if err != nil { + return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} + } + + localVarPath := localBasePath + "/runner/provider/for-install" + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHTTPContentTypes := []string{} + + // set Content-Type header + localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes) + if localVarHTTPContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHTTPContentType + } + + // to determine the Accept header + localVarHTTPHeaderAccepts := []string{"application/json"} + + // set Accept header + localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) + if localVarHTTPHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept + } + if r.ctx != nil { + // API Key Authentication + if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { + if apiKey, ok := auth["Bearer"]; ok { + var key string + if apiKey.Prefix != "" { + key = apiKey.Prefix + " " + apiKey.Key + } else { + key = apiKey.Key + } + localVarHeaderParams["Authorization"] = key + } + } + } + req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHTTPResponse, err := a.client.callAPI(req) + if err != nil || localVarHTTPResponse == nil { + return localVarReturnValue, localVarHTTPResponse, err + } + + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) + localVarHTTPResponse.Body.Close() + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) + if err != nil { + return localVarReturnValue, localVarHTTPResponse, err + } + + if localVarHTTPResponse.StatusCode >= 300 { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: localVarHTTPResponse.Status, + } + return localVarReturnValue, localVarHTTPResponse, newErr + } + + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: err.Error(), + } + return localVarReturnValue, localVarHTTPResponse, newErr + } + + return localVarReturnValue, localVarHTTPResponse, nil +} + +type ApiUninstallProviderRequest struct { + ctx context.Context + ApiService *ProviderAPIService + runnerId string + providerName string } func (r ApiUninstallProviderRequest) Execute() (*http.Response, error) { @@ -379,19 +510,21 @@ func (r ApiUninstallProviderRequest) Execute() (*http.Response, error) { } /* -UninstallProvider Uninstall a provider +UninstallProvider Uninstall provider -Uninstall a provider +Uninstall provider @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). - @param provider Provider to uninstall + @param runnerId Runner ID + @param providerName Provider name @return ApiUninstallProviderRequest */ -func (a *ProviderAPIService) UninstallProvider(ctx context.Context, provider string) ApiUninstallProviderRequest { +func (a *ProviderAPIService) UninstallProvider(ctx context.Context, runnerId string, providerName string) ApiUninstallProviderRequest { return ApiUninstallProviderRequest{ - ApiService: a, - ctx: ctx, - provider: provider, + ApiService: a, + ctx: ctx, + runnerId: runnerId, + providerName: providerName, } } @@ -408,8 +541,9 @@ func (a *ProviderAPIService) UninstallProviderExecute(r ApiUninstallProviderRequ return nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/provider/{provider}/uninstall" - localVarPath = strings.Replace(localVarPath, "{"+"provider"+"}", url.PathEscape(parameterValueToString(r.provider, "provider")), -1) + localVarPath := localBasePath + "/runner/{runnerId}/provider/{providerName}/uninstall" + localVarPath = strings.Replace(localVarPath, "{"+"runnerId"+"}", url.PathEscape(parameterValueToString(r.runnerId, "runnerId")), -1) + localVarPath = strings.Replace(localVarPath, "{"+"providerName"+"}", url.PathEscape(parameterValueToString(r.providerName, "providerName")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -473,3 +607,123 @@ func (a *ProviderAPIService) UninstallProviderExecute(r ApiUninstallProviderRequ return localVarHTTPResponse, nil } + +type ApiUpdateProviderRequest struct { + ctx context.Context + ApiService *ProviderAPIService + runnerId string + providerName string + providerVersion *string +} + +// Provider version - defaults to 'latest' +func (r ApiUpdateProviderRequest) ProviderVersion(providerVersion string) ApiUpdateProviderRequest { + r.providerVersion = &providerVersion + return r +} + +func (r ApiUpdateProviderRequest) Execute() (*http.Response, error) { + return r.ApiService.UpdateProviderExecute(r) +} + +/* +UpdateProvider Update provider + +Update provider + + @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + @param runnerId Runner ID + @param providerName Provider name + @return ApiUpdateProviderRequest +*/ +func (a *ProviderAPIService) UpdateProvider(ctx context.Context, runnerId string, providerName string) ApiUpdateProviderRequest { + return ApiUpdateProviderRequest{ + ApiService: a, + ctx: ctx, + runnerId: runnerId, + providerName: providerName, + } +} + +// Execute executes the request +func (a *ProviderAPIService) UpdateProviderExecute(r ApiUpdateProviderRequest) (*http.Response, error) { + var ( + localVarHTTPMethod = http.MethodPost + localVarPostBody interface{} + formFiles []formFile + ) + + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "ProviderAPIService.UpdateProvider") + if err != nil { + return nil, &GenericOpenAPIError{error: err.Error()} + } + + localVarPath := localBasePath + "/runner/{runnerId}/provider/{providerName}/update" + localVarPath = strings.Replace(localVarPath, "{"+"runnerId"+"}", url.PathEscape(parameterValueToString(r.runnerId, "runnerId")), -1) + localVarPath = strings.Replace(localVarPath, "{"+"providerName"+"}", url.PathEscape(parameterValueToString(r.providerName, "providerName")), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + if r.providerVersion != nil { + parameterAddToHeaderOrQuery(localVarQueryParams, "providerVersion", r.providerVersion, "") + } + // to determine the Content-Type header + localVarHTTPContentTypes := []string{} + + // set Content-Type header + localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes) + if localVarHTTPContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHTTPContentType + } + + // to determine the Accept header + localVarHTTPHeaderAccepts := []string{} + + // set Accept header + localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) + if localVarHTTPHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept + } + if r.ctx != nil { + // API Key Authentication + if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { + if apiKey, ok := auth["Bearer"]; ok { + var key string + if apiKey.Prefix != "" { + key = apiKey.Prefix + " " + apiKey.Key + } else { + key = apiKey.Key + } + localVarHeaderParams["Authorization"] = key + } + } + } + req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles) + if err != nil { + return nil, err + } + + localVarHTTPResponse, err := a.client.callAPI(req) + if err != nil || localVarHTTPResponse == nil { + return localVarHTTPResponse, err + } + + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) + localVarHTTPResponse.Body.Close() + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) + if err != nil { + return localVarHTTPResponse, err + } + + if localVarHTTPResponse.StatusCode >= 300 { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: localVarHTTPResponse.Status, + } + return localVarHTTPResponse, newErr + } + + return localVarHTTPResponse, nil +} diff --git a/pkg/apiclient/api_runner.go b/pkg/apiclient/api_runner.go new file mode 100644 index 0000000000..0c32123000 --- /dev/null +++ b/pkg/apiclient/api_runner.go @@ -0,0 +1,845 @@ +/* +Daytona Server API + +Daytona Server API + +API version: v0.0.0-dev +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package apiclient + +import ( + "bytes" + "context" + "io" + "net/http" + "net/url" + "strings" +) + +// RunnerAPIService RunnerAPI service +type RunnerAPIService service + +type ApiCreateRunnerRequest struct { + ctx context.Context + ApiService *RunnerAPIService + runner *CreateRunnerDTO +} + +// Runner +func (r ApiCreateRunnerRequest) Runner(runner CreateRunnerDTO) ApiCreateRunnerRequest { + r.runner = &runner + return r +} + +func (r ApiCreateRunnerRequest) Execute() (*CreateRunnerResultDTO, *http.Response, error) { + return r.ApiService.CreateRunnerExecute(r) +} + +/* +CreateRunner Create a runner + +Create a runner + + @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + @return ApiCreateRunnerRequest +*/ +func (a *RunnerAPIService) CreateRunner(ctx context.Context) ApiCreateRunnerRequest { + return ApiCreateRunnerRequest{ + ApiService: a, + ctx: ctx, + } +} + +// Execute executes the request +// +// @return CreateRunnerResultDTO +func (a *RunnerAPIService) CreateRunnerExecute(r ApiCreateRunnerRequest) (*CreateRunnerResultDTO, *http.Response, error) { + var ( + localVarHTTPMethod = http.MethodPost + localVarPostBody interface{} + formFiles []formFile + localVarReturnValue *CreateRunnerResultDTO + ) + + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "RunnerAPIService.CreateRunner") + if err != nil { + return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} + } + + localVarPath := localBasePath + "/runner" + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + if r.runner == nil { + return localVarReturnValue, nil, reportError("runner is required and must be specified") + } + + // to determine the Content-Type header + localVarHTTPContentTypes := []string{} + + // set Content-Type header + localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes) + if localVarHTTPContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHTTPContentType + } + + // to determine the Accept header + localVarHTTPHeaderAccepts := []string{"application/json"} + + // set Accept header + localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) + if localVarHTTPHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept + } + // body params + localVarPostBody = r.runner + if r.ctx != nil { + // API Key Authentication + if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { + if apiKey, ok := auth["Bearer"]; ok { + var key string + if apiKey.Prefix != "" { + key = apiKey.Prefix + " " + apiKey.Key + } else { + key = apiKey.Key + } + localVarHeaderParams["Authorization"] = key + } + } + } + req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHTTPResponse, err := a.client.callAPI(req) + if err != nil || localVarHTTPResponse == nil { + return localVarReturnValue, localVarHTTPResponse, err + } + + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) + localVarHTTPResponse.Body.Close() + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) + if err != nil { + return localVarReturnValue, localVarHTTPResponse, err + } + + if localVarHTTPResponse.StatusCode >= 300 { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: localVarHTTPResponse.Status, + } + return localVarReturnValue, localVarHTTPResponse, newErr + } + + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: err.Error(), + } + return localVarReturnValue, localVarHTTPResponse, newErr + } + + return localVarReturnValue, localVarHTTPResponse, nil +} + +type ApiDeleteRunnerRequest struct { + ctx context.Context + ApiService *RunnerAPIService + runnerId string +} + +func (r ApiDeleteRunnerRequest) Execute() (*http.Response, error) { + return r.ApiService.DeleteRunnerExecute(r) +} + +/* +DeleteRunner Delete runner + +Delete runner + + @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + @param runnerId Runner ID + @return ApiDeleteRunnerRequest +*/ +func (a *RunnerAPIService) DeleteRunner(ctx context.Context, runnerId string) ApiDeleteRunnerRequest { + return ApiDeleteRunnerRequest{ + ApiService: a, + ctx: ctx, + runnerId: runnerId, + } +} + +// Execute executes the request +func (a *RunnerAPIService) DeleteRunnerExecute(r ApiDeleteRunnerRequest) (*http.Response, error) { + var ( + localVarHTTPMethod = http.MethodDelete + localVarPostBody interface{} + formFiles []formFile + ) + + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "RunnerAPIService.DeleteRunner") + if err != nil { + return nil, &GenericOpenAPIError{error: err.Error()} + } + + localVarPath := localBasePath + "/runner/{runnerId}" + localVarPath = strings.Replace(localVarPath, "{"+"runnerId"+"}", url.PathEscape(parameterValueToString(r.runnerId, "runnerId")), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHTTPContentTypes := []string{} + + // set Content-Type header + localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes) + if localVarHTTPContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHTTPContentType + } + + // to determine the Accept header + localVarHTTPHeaderAccepts := []string{} + + // set Accept header + localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) + if localVarHTTPHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept + } + if r.ctx != nil { + // API Key Authentication + if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { + if apiKey, ok := auth["Bearer"]; ok { + var key string + if apiKey.Prefix != "" { + key = apiKey.Prefix + " " + apiKey.Key + } else { + key = apiKey.Key + } + localVarHeaderParams["Authorization"] = key + } + } + } + req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles) + if err != nil { + return nil, err + } + + localVarHTTPResponse, err := a.client.callAPI(req) + if err != nil || localVarHTTPResponse == nil { + return localVarHTTPResponse, err + } + + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) + localVarHTTPResponse.Body.Close() + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) + if err != nil { + return localVarHTTPResponse, err + } + + if localVarHTTPResponse.StatusCode >= 300 { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: localVarHTTPResponse.Status, + } + return localVarHTTPResponse, newErr + } + + return localVarHTTPResponse, nil +} + +type ApiFindRunnerRequest struct { + ctx context.Context + ApiService *RunnerAPIService + runnerId string +} + +func (r ApiFindRunnerRequest) Execute() (*RunnerDTO, *http.Response, error) { + return r.ApiService.FindRunnerExecute(r) +} + +/* +FindRunner Find a runner + +Find a runner + + @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + @param runnerId Runner ID + @return ApiFindRunnerRequest +*/ +func (a *RunnerAPIService) FindRunner(ctx context.Context, runnerId string) ApiFindRunnerRequest { + return ApiFindRunnerRequest{ + ApiService: a, + ctx: ctx, + runnerId: runnerId, + } +} + +// Execute executes the request +// +// @return RunnerDTO +func (a *RunnerAPIService) FindRunnerExecute(r ApiFindRunnerRequest) (*RunnerDTO, *http.Response, error) { + var ( + localVarHTTPMethod = http.MethodGet + localVarPostBody interface{} + formFiles []formFile + localVarReturnValue *RunnerDTO + ) + + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "RunnerAPIService.FindRunner") + if err != nil { + return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} + } + + localVarPath := localBasePath + "/runner/{runnerId}" + localVarPath = strings.Replace(localVarPath, "{"+"runnerId"+"}", url.PathEscape(parameterValueToString(r.runnerId, "runnerId")), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHTTPContentTypes := []string{} + + // set Content-Type header + localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes) + if localVarHTTPContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHTTPContentType + } + + // to determine the Accept header + localVarHTTPHeaderAccepts := []string{"application/json"} + + // set Accept header + localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) + if localVarHTTPHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept + } + if r.ctx != nil { + // API Key Authentication + if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { + if apiKey, ok := auth["Bearer"]; ok { + var key string + if apiKey.Prefix != "" { + key = apiKey.Prefix + " " + apiKey.Key + } else { + key = apiKey.Key + } + localVarHeaderParams["Authorization"] = key + } + } + } + req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHTTPResponse, err := a.client.callAPI(req) + if err != nil || localVarHTTPResponse == nil { + return localVarReturnValue, localVarHTTPResponse, err + } + + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) + localVarHTTPResponse.Body.Close() + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) + if err != nil { + return localVarReturnValue, localVarHTTPResponse, err + } + + if localVarHTTPResponse.StatusCode >= 300 { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: localVarHTTPResponse.Status, + } + return localVarReturnValue, localVarHTTPResponse, newErr + } + + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: err.Error(), + } + return localVarReturnValue, localVarHTTPResponse, newErr + } + + return localVarReturnValue, localVarHTTPResponse, nil +} + +type ApiListRunnerJobsRequest struct { + ctx context.Context + ApiService *RunnerAPIService + runnerId string +} + +func (r ApiListRunnerJobsRequest) Execute() ([]Job, *http.Response, error) { + return r.ApiService.ListRunnerJobsExecute(r) +} + +/* +ListRunnerJobs List runner jobs + +List runner jobs + + @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + @param runnerId Runner ID + @return ApiListRunnerJobsRequest +*/ +func (a *RunnerAPIService) ListRunnerJobs(ctx context.Context, runnerId string) ApiListRunnerJobsRequest { + return ApiListRunnerJobsRequest{ + ApiService: a, + ctx: ctx, + runnerId: runnerId, + } +} + +// Execute executes the request +// +// @return []Job +func (a *RunnerAPIService) ListRunnerJobsExecute(r ApiListRunnerJobsRequest) ([]Job, *http.Response, error) { + var ( + localVarHTTPMethod = http.MethodGet + localVarPostBody interface{} + formFiles []formFile + localVarReturnValue []Job + ) + + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "RunnerAPIService.ListRunnerJobs") + if err != nil { + return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} + } + + localVarPath := localBasePath + "/runner/{runnerId}/jobs" + localVarPath = strings.Replace(localVarPath, "{"+"runnerId"+"}", url.PathEscape(parameterValueToString(r.runnerId, "runnerId")), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHTTPContentTypes := []string{} + + // set Content-Type header + localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes) + if localVarHTTPContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHTTPContentType + } + + // to determine the Accept header + localVarHTTPHeaderAccepts := []string{"application/json"} + + // set Accept header + localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) + if localVarHTTPHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept + } + if r.ctx != nil { + // API Key Authentication + if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { + if apiKey, ok := auth["Bearer"]; ok { + var key string + if apiKey.Prefix != "" { + key = apiKey.Prefix + " " + apiKey.Key + } else { + key = apiKey.Key + } + localVarHeaderParams["Authorization"] = key + } + } + } + req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHTTPResponse, err := a.client.callAPI(req) + if err != nil || localVarHTTPResponse == nil { + return localVarReturnValue, localVarHTTPResponse, err + } + + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) + localVarHTTPResponse.Body.Close() + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) + if err != nil { + return localVarReturnValue, localVarHTTPResponse, err + } + + if localVarHTTPResponse.StatusCode >= 300 { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: localVarHTTPResponse.Status, + } + return localVarReturnValue, localVarHTTPResponse, newErr + } + + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: err.Error(), + } + return localVarReturnValue, localVarHTTPResponse, newErr + } + + return localVarReturnValue, localVarHTTPResponse, nil +} + +type ApiListRunnersRequest struct { + ctx context.Context + ApiService *RunnerAPIService +} + +func (r ApiListRunnersRequest) Execute() ([]RunnerDTO, *http.Response, error) { + return r.ApiService.ListRunnersExecute(r) +} + +/* +ListRunners List runners + +List runners + + @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + @return ApiListRunnersRequest +*/ +func (a *RunnerAPIService) ListRunners(ctx context.Context) ApiListRunnersRequest { + return ApiListRunnersRequest{ + ApiService: a, + ctx: ctx, + } +} + +// Execute executes the request +// +// @return []RunnerDTO +func (a *RunnerAPIService) ListRunnersExecute(r ApiListRunnersRequest) ([]RunnerDTO, *http.Response, error) { + var ( + localVarHTTPMethod = http.MethodGet + localVarPostBody interface{} + formFiles []formFile + localVarReturnValue []RunnerDTO + ) + + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "RunnerAPIService.ListRunners") + if err != nil { + return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} + } + + localVarPath := localBasePath + "/runner" + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHTTPContentTypes := []string{} + + // set Content-Type header + localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes) + if localVarHTTPContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHTTPContentType + } + + // to determine the Accept header + localVarHTTPHeaderAccepts := []string{"application/json"} + + // set Accept header + localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) + if localVarHTTPHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept + } + if r.ctx != nil { + // API Key Authentication + if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { + if apiKey, ok := auth["Bearer"]; ok { + var key string + if apiKey.Prefix != "" { + key = apiKey.Prefix + " " + apiKey.Key + } else { + key = apiKey.Key + } + localVarHeaderParams["Authorization"] = key + } + } + } + req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHTTPResponse, err := a.client.callAPI(req) + if err != nil || localVarHTTPResponse == nil { + return localVarReturnValue, localVarHTTPResponse, err + } + + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) + localVarHTTPResponse.Body.Close() + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) + if err != nil { + return localVarReturnValue, localVarHTTPResponse, err + } + + if localVarHTTPResponse.StatusCode >= 300 { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: localVarHTTPResponse.Status, + } + return localVarReturnValue, localVarHTTPResponse, newErr + } + + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: err.Error(), + } + return localVarReturnValue, localVarHTTPResponse, newErr + } + + return localVarReturnValue, localVarHTTPResponse, nil +} + +type ApiUpdateJobStateRequest struct { + ctx context.Context + ApiService *RunnerAPIService + runnerId string + jobId string + updateJobState *UpdateJobState +} + +// Update job state +func (r ApiUpdateJobStateRequest) UpdateJobState(updateJobState UpdateJobState) ApiUpdateJobStateRequest { + r.updateJobState = &updateJobState + return r +} + +func (r ApiUpdateJobStateRequest) Execute() (*http.Response, error) { + return r.ApiService.UpdateJobStateExecute(r) +} + +/* +UpdateJobState Update job state + +Update job state + + @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + @param runnerId Runner ID + @param jobId Job ID + @return ApiUpdateJobStateRequest +*/ +func (a *RunnerAPIService) UpdateJobState(ctx context.Context, runnerId string, jobId string) ApiUpdateJobStateRequest { + return ApiUpdateJobStateRequest{ + ApiService: a, + ctx: ctx, + runnerId: runnerId, + jobId: jobId, + } +} + +// Execute executes the request +func (a *RunnerAPIService) UpdateJobStateExecute(r ApiUpdateJobStateRequest) (*http.Response, error) { + var ( + localVarHTTPMethod = http.MethodPost + localVarPostBody interface{} + formFiles []formFile + ) + + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "RunnerAPIService.UpdateJobState") + if err != nil { + return nil, &GenericOpenAPIError{error: err.Error()} + } + + localVarPath := localBasePath + "/runner/{runnerId}/jobs/{jobId}/state" + localVarPath = strings.Replace(localVarPath, "{"+"runnerId"+"}", url.PathEscape(parameterValueToString(r.runnerId, "runnerId")), -1) + localVarPath = strings.Replace(localVarPath, "{"+"jobId"+"}", url.PathEscape(parameterValueToString(r.jobId, "jobId")), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + if r.updateJobState == nil { + return nil, reportError("updateJobState is required and must be specified") + } + + // to determine the Content-Type header + localVarHTTPContentTypes := []string{} + + // set Content-Type header + localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes) + if localVarHTTPContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHTTPContentType + } + + // to determine the Accept header + localVarHTTPHeaderAccepts := []string{} + + // set Accept header + localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) + if localVarHTTPHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept + } + // body params + localVarPostBody = r.updateJobState + if r.ctx != nil { + // API Key Authentication + if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { + if apiKey, ok := auth["Bearer"]; ok { + var key string + if apiKey.Prefix != "" { + key = apiKey.Prefix + " " + apiKey.Key + } else { + key = apiKey.Key + } + localVarHeaderParams["Authorization"] = key + } + } + } + req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles) + if err != nil { + return nil, err + } + + localVarHTTPResponse, err := a.client.callAPI(req) + if err != nil || localVarHTTPResponse == nil { + return localVarHTTPResponse, err + } + + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) + localVarHTTPResponse.Body.Close() + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) + if err != nil { + return localVarHTTPResponse, err + } + + if localVarHTTPResponse.StatusCode >= 300 { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: localVarHTTPResponse.Status, + } + return localVarHTTPResponse, newErr + } + + return localVarHTTPResponse, nil +} + +type ApiUpdateRunnerMetadataRequest struct { + ctx context.Context + ApiService *RunnerAPIService + runnerId string + runnerMetadata *UpdateRunnerMetadataDTO +} + +// Runner Metadata +func (r ApiUpdateRunnerMetadataRequest) RunnerMetadata(runnerMetadata UpdateRunnerMetadataDTO) ApiUpdateRunnerMetadataRequest { + r.runnerMetadata = &runnerMetadata + return r +} + +func (r ApiUpdateRunnerMetadataRequest) Execute() (*http.Response, error) { + return r.ApiService.UpdateRunnerMetadataExecute(r) +} + +/* +UpdateRunnerMetadata Update runner metadata + +Update runner metadata + + @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + @param runnerId Runner ID + @return ApiUpdateRunnerMetadataRequest +*/ +func (a *RunnerAPIService) UpdateRunnerMetadata(ctx context.Context, runnerId string) ApiUpdateRunnerMetadataRequest { + return ApiUpdateRunnerMetadataRequest{ + ApiService: a, + ctx: ctx, + runnerId: runnerId, + } +} + +// Execute executes the request +func (a *RunnerAPIService) UpdateRunnerMetadataExecute(r ApiUpdateRunnerMetadataRequest) (*http.Response, error) { + var ( + localVarHTTPMethod = http.MethodPost + localVarPostBody interface{} + formFiles []formFile + ) + + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "RunnerAPIService.UpdateRunnerMetadata") + if err != nil { + return nil, &GenericOpenAPIError{error: err.Error()} + } + + localVarPath := localBasePath + "/runner/{runnerId}/metadata" + localVarPath = strings.Replace(localVarPath, "{"+"runnerId"+"}", url.PathEscape(parameterValueToString(r.runnerId, "runnerId")), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + if r.runnerMetadata == nil { + return nil, reportError("runnerMetadata is required and must be specified") + } + + // to determine the Content-Type header + localVarHTTPContentTypes := []string{} + + // set Content-Type header + localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes) + if localVarHTTPContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHTTPContentType + } + + // to determine the Accept header + localVarHTTPHeaderAccepts := []string{} + + // set Accept header + localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) + if localVarHTTPHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept + } + // body params + localVarPostBody = r.runnerMetadata + if r.ctx != nil { + // API Key Authentication + if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { + if apiKey, ok := auth["Bearer"]; ok { + var key string + if apiKey.Prefix != "" { + key = apiKey.Prefix + " " + apiKey.Key + } else { + key = apiKey.Key + } + localVarHeaderParams["Authorization"] = key + } + } + } + req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles) + if err != nil { + return nil, err + } + + localVarHTTPResponse, err := a.client.callAPI(req) + if err != nil || localVarHTTPResponse == nil { + return localVarHTTPResponse, err + } + + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) + localVarHTTPResponse.Body.Close() + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) + if err != nil { + return localVarHTTPResponse, err + } + + if localVarHTTPResponse.StatusCode >= 300 { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: localVarHTTPResponse.Status, + } + return localVarHTTPResponse, newErr + } + + return localVarHTTPResponse, nil +} diff --git a/pkg/apiclient/api_server.go b/pkg/apiclient/api_server.go index ee89a12b8c..6fce8c1e6e 100644 --- a/pkg/apiclient/api_server.go +++ b/pkg/apiclient/api_server.go @@ -21,25 +21,25 @@ import ( // ServerAPIService ServerAPI service type ServerAPIService service -type ApiGenerateNetworkKeyRequest struct { +type ApiCreateNetworkKeyRequest struct { ctx context.Context ApiService *ServerAPIService } -func (r ApiGenerateNetworkKeyRequest) Execute() (*NetworkKey, *http.Response, error) { - return r.ApiService.GenerateNetworkKeyExecute(r) +func (r ApiCreateNetworkKeyRequest) Execute() (*NetworkKey, *http.Response, error) { + return r.ApiService.CreateNetworkKeyExecute(r) } /* -GenerateNetworkKey Generate a new authentication key +CreateNetworkKey Create a new authentication key -Generate a new authentication key +Create a new authentication key @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). - @return ApiGenerateNetworkKeyRequest + @return ApiCreateNetworkKeyRequest */ -func (a *ServerAPIService) GenerateNetworkKey(ctx context.Context) ApiGenerateNetworkKeyRequest { - return ApiGenerateNetworkKeyRequest{ +func (a *ServerAPIService) CreateNetworkKey(ctx context.Context) ApiCreateNetworkKeyRequest { + return ApiCreateNetworkKeyRequest{ ApiService: a, ctx: ctx, } @@ -48,7 +48,7 @@ func (a *ServerAPIService) GenerateNetworkKey(ctx context.Context) ApiGenerateNe // Execute executes the request // // @return NetworkKey -func (a *ServerAPIService) GenerateNetworkKeyExecute(r ApiGenerateNetworkKeyRequest) (*NetworkKey, *http.Response, error) { +func (a *ServerAPIService) CreateNetworkKeyExecute(r ApiCreateNetworkKeyRequest) (*NetworkKey, *http.Response, error) { var ( localVarHTTPMethod = http.MethodPost localVarPostBody interface{} @@ -56,7 +56,7 @@ func (a *ServerAPIService) GenerateNetworkKeyExecute(r ApiGenerateNetworkKeyRequ localVarReturnValue *NetworkKey ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "ServerAPIService.GenerateNetworkKey") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "ServerAPIService.CreateNetworkKey") if err != nil { return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } @@ -259,9 +259,9 @@ func (r ApiGetServerLogFilesRequest) Execute() ([]string, *http.Response, error) } /* -GetServerLogFiles List server log files +GetServerLogFiles Get server log files -List server log files +Get server log files @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @return ApiGetServerLogFilesRequest @@ -363,32 +363,32 @@ func (a *ServerAPIService) GetServerLogFilesExecute(r ApiGetServerLogFilesReques return localVarReturnValue, localVarHTTPResponse, nil } -type ApiSetConfigRequest struct { +type ApiSaveConfigRequest struct { ctx context.Context ApiService *ServerAPIService config *ServerConfig } // Server configuration -func (r ApiSetConfigRequest) Config(config ServerConfig) ApiSetConfigRequest { +func (r ApiSaveConfigRequest) Config(config ServerConfig) ApiSaveConfigRequest { r.config = &config return r } -func (r ApiSetConfigRequest) Execute() (*ServerConfig, *http.Response, error) { - return r.ApiService.SetConfigExecute(r) +func (r ApiSaveConfigRequest) Execute() (*ServerConfig, *http.Response, error) { + return r.ApiService.SaveConfigExecute(r) } /* -SetConfig Set the server configuration +SaveConfig Save the server configuration -Set the server configuration +Save the server configuration @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). - @return ApiSetConfigRequest + @return ApiSaveConfigRequest */ -func (a *ServerAPIService) SetConfig(ctx context.Context) ApiSetConfigRequest { - return ApiSetConfigRequest{ +func (a *ServerAPIService) SaveConfig(ctx context.Context) ApiSaveConfigRequest { + return ApiSaveConfigRequest{ ApiService: a, ctx: ctx, } @@ -397,15 +397,15 @@ func (a *ServerAPIService) SetConfig(ctx context.Context) ApiSetConfigRequest { // Execute executes the request // // @return ServerConfig -func (a *ServerAPIService) SetConfigExecute(r ApiSetConfigRequest) (*ServerConfig, *http.Response, error) { +func (a *ServerAPIService) SaveConfigExecute(r ApiSaveConfigRequest) (*ServerConfig, *http.Response, error) { var ( - localVarHTTPMethod = http.MethodPost + localVarHTTPMethod = http.MethodPut localVarPostBody interface{} formFiles []formFile localVarReturnValue *ServerConfig ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "ServerAPIService.SetConfig") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "ServerAPIService.SaveConfig") if err != nil { return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } diff --git a/pkg/apiclient/api_target.go b/pkg/apiclient/api_target.go index 09ace864e4..02c7673847 100644 --- a/pkg/apiclient/api_target.go +++ b/pkg/apiclient/api_target.go @@ -22,25 +22,32 @@ import ( // TargetAPIService TargetAPI service type TargetAPIService service -type ApiListTargetsRequest struct { +type ApiCreateTargetRequest struct { ctx context.Context ApiService *TargetAPIService + target *CreateTargetDTO } -func (r ApiListTargetsRequest) Execute() ([]ProviderTarget, *http.Response, error) { - return r.ApiService.ListTargetsExecute(r) +// Create target +func (r ApiCreateTargetRequest) Target(target CreateTargetDTO) ApiCreateTargetRequest { + r.target = &target + return r +} + +func (r ApiCreateTargetRequest) Execute() (*Target, *http.Response, error) { + return r.ApiService.CreateTargetExecute(r) } /* -ListTargets List targets +CreateTarget Create a target -List targets +Create a target @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). - @return ApiListTargetsRequest + @return ApiCreateTargetRequest */ -func (a *TargetAPIService) ListTargets(ctx context.Context) ApiListTargetsRequest { - return ApiListTargetsRequest{ +func (a *TargetAPIService) CreateTarget(ctx context.Context) ApiCreateTargetRequest { + return ApiCreateTargetRequest{ ApiService: a, ctx: ctx, } @@ -48,16 +55,16 @@ func (a *TargetAPIService) ListTargets(ctx context.Context) ApiListTargetsReques // Execute executes the request // -// @return []ProviderTarget -func (a *TargetAPIService) ListTargetsExecute(r ApiListTargetsRequest) ([]ProviderTarget, *http.Response, error) { +// @return Target +func (a *TargetAPIService) CreateTargetExecute(r ApiCreateTargetRequest) (*Target, *http.Response, error) { var ( - localVarHTTPMethod = http.MethodGet + localVarHTTPMethod = http.MethodPost localVarPostBody interface{} formFiles []formFile - localVarReturnValue []ProviderTarget + localVarReturnValue *Target ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "TargetAPIService.ListTargets") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "TargetAPIService.CreateTarget") if err != nil { return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } @@ -67,6 +74,9 @@ func (a *TargetAPIService) ListTargetsExecute(r ApiListTargetsRequest) ([]Provid localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} localVarFormParams := url.Values{} + if r.target == nil { + return localVarReturnValue, nil, reportError("target is required and must be specified") + } // to determine the Content-Type header localVarHTTPContentTypes := []string{} @@ -85,6 +95,8 @@ func (a *TargetAPIService) ListTargetsExecute(r ApiListTargetsRequest) ([]Provid if localVarHTTPHeaderAccept != "" { localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept } + // body params + localVarPostBody = r.target if r.ctx != nil { // API Key Authentication if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { @@ -136,53 +148,63 @@ func (a *TargetAPIService) ListTargetsExecute(r ApiListTargetsRequest) ([]Provid return localVarReturnValue, localVarHTTPResponse, nil } -type ApiRemoveTargetRequest struct { +type ApiDeleteTargetRequest struct { ctx context.Context ApiService *TargetAPIService - target string + targetId string + force *bool +} + +// Force +func (r ApiDeleteTargetRequest) Force(force bool) ApiDeleteTargetRequest { + r.force = &force + return r } -func (r ApiRemoveTargetRequest) Execute() (*http.Response, error) { - return r.ApiService.RemoveTargetExecute(r) +func (r ApiDeleteTargetRequest) Execute() (*http.Response, error) { + return r.ApiService.DeleteTargetExecute(r) } /* -RemoveTarget Remove a target +DeleteTarget Delete target -Remove a target +Delete target @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). - @param target Target name - @return ApiRemoveTargetRequest + @param targetId Target ID + @return ApiDeleteTargetRequest */ -func (a *TargetAPIService) RemoveTarget(ctx context.Context, target string) ApiRemoveTargetRequest { - return ApiRemoveTargetRequest{ +func (a *TargetAPIService) DeleteTarget(ctx context.Context, targetId string) ApiDeleteTargetRequest { + return ApiDeleteTargetRequest{ ApiService: a, ctx: ctx, - target: target, + targetId: targetId, } } // Execute executes the request -func (a *TargetAPIService) RemoveTargetExecute(r ApiRemoveTargetRequest) (*http.Response, error) { +func (a *TargetAPIService) DeleteTargetExecute(r ApiDeleteTargetRequest) (*http.Response, error) { var ( localVarHTTPMethod = http.MethodDelete localVarPostBody interface{} formFiles []formFile ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "TargetAPIService.RemoveTarget") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "TargetAPIService.DeleteTarget") if err != nil { return nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/target/{target}" - localVarPath = strings.Replace(localVarPath, "{"+"target"+"}", url.PathEscape(parameterValueToString(r.target, "target")), -1) + localVarPath := localBasePath + "/target/{targetId}" + localVarPath = strings.Replace(localVarPath, "{"+"targetId"+"}", url.PathEscape(parameterValueToString(r.targetId, "targetId")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} localVarFormParams := url.Values{} + if r.force != nil { + parameterAddToHeaderOrQuery(localVarQueryParams, "force", r.force, "") + } // to determine the Content-Type header localVarHTTPContentTypes := []string{} @@ -242,48 +264,294 @@ func (a *TargetAPIService) RemoveTargetExecute(r ApiRemoveTargetRequest) (*http. return localVarHTTPResponse, nil } -type ApiSetDefaultTargetRequest struct { +type ApiFindTargetRequest struct { + ctx context.Context + ApiService *TargetAPIService + targetId string + showOptions *bool +} + +// Show target config options +func (r ApiFindTargetRequest) ShowOptions(showOptions bool) ApiFindTargetRequest { + r.showOptions = &showOptions + return r +} + +func (r ApiFindTargetRequest) Execute() (*TargetDTO, *http.Response, error) { + return r.ApiService.FindTargetExecute(r) +} + +/* +FindTarget Find target + +Find target + + @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + @param targetId Target ID or Name + @return ApiFindTargetRequest +*/ +func (a *TargetAPIService) FindTarget(ctx context.Context, targetId string) ApiFindTargetRequest { + return ApiFindTargetRequest{ + ApiService: a, + ctx: ctx, + targetId: targetId, + } +} + +// Execute executes the request +// +// @return TargetDTO +func (a *TargetAPIService) FindTargetExecute(r ApiFindTargetRequest) (*TargetDTO, *http.Response, error) { + var ( + localVarHTTPMethod = http.MethodGet + localVarPostBody interface{} + formFiles []formFile + localVarReturnValue *TargetDTO + ) + + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "TargetAPIService.FindTarget") + if err != nil { + return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} + } + + localVarPath := localBasePath + "/target/{targetId}" + localVarPath = strings.Replace(localVarPath, "{"+"targetId"+"}", url.PathEscape(parameterValueToString(r.targetId, "targetId")), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + if r.showOptions != nil { + parameterAddToHeaderOrQuery(localVarQueryParams, "showOptions", r.showOptions, "") + } + // to determine the Content-Type header + localVarHTTPContentTypes := []string{} + + // set Content-Type header + localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes) + if localVarHTTPContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHTTPContentType + } + + // to determine the Accept header + localVarHTTPHeaderAccepts := []string{"application/json"} + + // set Accept header + localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) + if localVarHTTPHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept + } + if r.ctx != nil { + // API Key Authentication + if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { + if apiKey, ok := auth["Bearer"]; ok { + var key string + if apiKey.Prefix != "" { + key = apiKey.Prefix + " " + apiKey.Key + } else { + key = apiKey.Key + } + localVarHeaderParams["Authorization"] = key + } + } + } + req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHTTPResponse, err := a.client.callAPI(req) + if err != nil || localVarHTTPResponse == nil { + return localVarReturnValue, localVarHTTPResponse, err + } + + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) + localVarHTTPResponse.Body.Close() + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) + if err != nil { + return localVarReturnValue, localVarHTTPResponse, err + } + + if localVarHTTPResponse.StatusCode >= 300 { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: localVarHTTPResponse.Status, + } + return localVarReturnValue, localVarHTTPResponse, newErr + } + + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: err.Error(), + } + return localVarReturnValue, localVarHTTPResponse, newErr + } + + return localVarReturnValue, localVarHTTPResponse, nil +} + +type ApiGetTargetStateRequest struct { ctx context.Context ApiService *TargetAPIService - target string + targetId string } -func (r ApiSetDefaultTargetRequest) Execute() (*http.Response, error) { - return r.ApiService.SetDefaultTargetExecute(r) +func (r ApiGetTargetStateRequest) Execute() (*ResourceState, *http.Response, error) { + return r.ApiService.GetTargetStateExecute(r) } /* -SetDefaultTarget Set target to default +GetTargetState Get target state -Set target to default +Get target state @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). - @param target Target name - @return ApiSetDefaultTargetRequest + @param targetId Target ID or Name + @return ApiGetTargetStateRequest */ -func (a *TargetAPIService) SetDefaultTarget(ctx context.Context, target string) ApiSetDefaultTargetRequest { - return ApiSetDefaultTargetRequest{ +func (a *TargetAPIService) GetTargetState(ctx context.Context, targetId string) ApiGetTargetStateRequest { + return ApiGetTargetStateRequest{ ApiService: a, ctx: ctx, - target: target, + targetId: targetId, } } // Execute executes the request -func (a *TargetAPIService) SetDefaultTargetExecute(r ApiSetDefaultTargetRequest) (*http.Response, error) { +// +// @return ResourceState +func (a *TargetAPIService) GetTargetStateExecute(r ApiGetTargetStateRequest) (*ResourceState, *http.Response, error) { var ( - localVarHTTPMethod = http.MethodPatch + localVarHTTPMethod = http.MethodGet + localVarPostBody interface{} + formFiles []formFile + localVarReturnValue *ResourceState + ) + + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "TargetAPIService.GetTargetState") + if err != nil { + return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} + } + + localVarPath := localBasePath + "/target/{targetId}/state" + localVarPath = strings.Replace(localVarPath, "{"+"targetId"+"}", url.PathEscape(parameterValueToString(r.targetId, "targetId")), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHTTPContentTypes := []string{} + + // set Content-Type header + localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes) + if localVarHTTPContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHTTPContentType + } + + // to determine the Accept header + localVarHTTPHeaderAccepts := []string{"application/json"} + + // set Accept header + localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) + if localVarHTTPHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept + } + if r.ctx != nil { + // API Key Authentication + if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { + if apiKey, ok := auth["Bearer"]; ok { + var key string + if apiKey.Prefix != "" { + key = apiKey.Prefix + " " + apiKey.Key + } else { + key = apiKey.Key + } + localVarHeaderParams["Authorization"] = key + } + } + } + req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHTTPResponse, err := a.client.callAPI(req) + if err != nil || localVarHTTPResponse == nil { + return localVarReturnValue, localVarHTTPResponse, err + } + + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) + localVarHTTPResponse.Body.Close() + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) + if err != nil { + return localVarReturnValue, localVarHTTPResponse, err + } + + if localVarHTTPResponse.StatusCode >= 300 { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: localVarHTTPResponse.Status, + } + return localVarReturnValue, localVarHTTPResponse, newErr + } + + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: err.Error(), + } + return localVarReturnValue, localVarHTTPResponse, newErr + } + + return localVarReturnValue, localVarHTTPResponse, nil +} + +type ApiHandleSuccessfulCreationRequest struct { + ctx context.Context + ApiService *TargetAPIService + targetId string +} + +func (r ApiHandleSuccessfulCreationRequest) Execute() (*http.Response, error) { + return r.ApiService.HandleSuccessfulCreationExecute(r) +} + +/* +HandleSuccessfulCreation Handles successful creation of the target + +Handles successful creation of the target + + @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + @param targetId Target ID or name + @return ApiHandleSuccessfulCreationRequest +*/ +func (a *TargetAPIService) HandleSuccessfulCreation(ctx context.Context, targetId string) ApiHandleSuccessfulCreationRequest { + return ApiHandleSuccessfulCreationRequest{ + ApiService: a, + ctx: ctx, + targetId: targetId, + } +} + +// Execute executes the request +func (a *TargetAPIService) HandleSuccessfulCreationExecute(r ApiHandleSuccessfulCreationRequest) (*http.Response, error) { + var ( + localVarHTTPMethod = http.MethodPost localVarPostBody interface{} formFiles []formFile ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "TargetAPIService.SetDefaultTarget") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "TargetAPIService.HandleSuccessfulCreation") if err != nil { return nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/target/{target}/set-default" - localVarPath = strings.Replace(localVarPath, "{"+"target"+"}", url.PathEscape(parameterValueToString(r.target, "target")), -1) + localVarPath := localBasePath + "/target/{targetId}/handle-successful-creation" + localVarPath = strings.Replace(localVarPath, "{"+"targetId"+"}", url.PathEscape(parameterValueToString(r.targetId, "targetId")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -348,48 +616,51 @@ func (a *TargetAPIService) SetDefaultTargetExecute(r ApiSetDefaultTargetRequest) return localVarHTTPResponse, nil } -type ApiSetTargetRequest struct { - ctx context.Context - ApiService *TargetAPIService - target *CreateProviderTargetDTO +type ApiListTargetsRequest struct { + ctx context.Context + ApiService *TargetAPIService + showOptions *bool } -// Target to set -func (r ApiSetTargetRequest) Target(target CreateProviderTargetDTO) ApiSetTargetRequest { - r.target = &target +// Show target config options +func (r ApiListTargetsRequest) ShowOptions(showOptions bool) ApiListTargetsRequest { + r.showOptions = &showOptions return r } -func (r ApiSetTargetRequest) Execute() (*http.Response, error) { - return r.ApiService.SetTargetExecute(r) +func (r ApiListTargetsRequest) Execute() ([]TargetDTO, *http.Response, error) { + return r.ApiService.ListTargetsExecute(r) } /* -SetTarget Set a target +ListTargets List targets -Set a target +List targets @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). - @return ApiSetTargetRequest + @return ApiListTargetsRequest */ -func (a *TargetAPIService) SetTarget(ctx context.Context) ApiSetTargetRequest { - return ApiSetTargetRequest{ +func (a *TargetAPIService) ListTargets(ctx context.Context) ApiListTargetsRequest { + return ApiListTargetsRequest{ ApiService: a, ctx: ctx, } } // Execute executes the request -func (a *TargetAPIService) SetTargetExecute(r ApiSetTargetRequest) (*http.Response, error) { +// +// @return []TargetDTO +func (a *TargetAPIService) ListTargetsExecute(r ApiListTargetsRequest) ([]TargetDTO, *http.Response, error) { var ( - localVarHTTPMethod = http.MethodPut - localVarPostBody interface{} - formFiles []formFile + localVarHTTPMethod = http.MethodGet + localVarPostBody interface{} + formFiles []formFile + localVarReturnValue []TargetDTO ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "TargetAPIService.SetTarget") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "TargetAPIService.ListTargets") if err != nil { - return nil, &GenericOpenAPIError{error: err.Error()} + return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } localVarPath := localBasePath + "/target" @@ -397,10 +668,10 @@ func (a *TargetAPIService) SetTargetExecute(r ApiSetTargetRequest) (*http.Respon localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} localVarFormParams := url.Values{} - if r.target == nil { - return nil, reportError("target is required and must be specified") - } + if r.showOptions != nil { + parameterAddToHeaderOrQuery(localVarQueryParams, "showOptions", r.showOptions, "") + } // to determine the Content-Type header localVarHTTPContentTypes := []string{} @@ -411,7 +682,556 @@ func (a *TargetAPIService) SetTargetExecute(r ApiSetTargetRequest) (*http.Respon } // to determine the Accept header - localVarHTTPHeaderAccepts := []string{} + localVarHTTPHeaderAccepts := []string{"application/json"} + + // set Accept header + localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) + if localVarHTTPHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept + } + if r.ctx != nil { + // API Key Authentication + if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { + if apiKey, ok := auth["Bearer"]; ok { + var key string + if apiKey.Prefix != "" { + key = apiKey.Prefix + " " + apiKey.Key + } else { + key = apiKey.Key + } + localVarHeaderParams["Authorization"] = key + } + } + } + req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHTTPResponse, err := a.client.callAPI(req) + if err != nil || localVarHTTPResponse == nil { + return localVarReturnValue, localVarHTTPResponse, err + } + + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) + localVarHTTPResponse.Body.Close() + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) + if err != nil { + return localVarReturnValue, localVarHTTPResponse, err + } + + if localVarHTTPResponse.StatusCode >= 300 { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: localVarHTTPResponse.Status, + } + return localVarReturnValue, localVarHTTPResponse, newErr + } + + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: err.Error(), + } + return localVarReturnValue, localVarHTTPResponse, newErr + } + + return localVarReturnValue, localVarHTTPResponse, nil +} + +type ApiRestartTargetRequest struct { + ctx context.Context + ApiService *TargetAPIService + targetId string +} + +func (r ApiRestartTargetRequest) Execute() (*http.Response, error) { + return r.ApiService.RestartTargetExecute(r) +} + +/* +RestartTarget Restart target + +Restart target + + @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + @param targetId Target ID or Name + @return ApiRestartTargetRequest +*/ +func (a *TargetAPIService) RestartTarget(ctx context.Context, targetId string) ApiRestartTargetRequest { + return ApiRestartTargetRequest{ + ApiService: a, + ctx: ctx, + targetId: targetId, + } +} + +// Execute executes the request +func (a *TargetAPIService) RestartTargetExecute(r ApiRestartTargetRequest) (*http.Response, error) { + var ( + localVarHTTPMethod = http.MethodPost + localVarPostBody interface{} + formFiles []formFile + ) + + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "TargetAPIService.RestartTarget") + if err != nil { + return nil, &GenericOpenAPIError{error: err.Error()} + } + + localVarPath := localBasePath + "/target/{targetId}/restart" + localVarPath = strings.Replace(localVarPath, "{"+"targetId"+"}", url.PathEscape(parameterValueToString(r.targetId, "targetId")), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHTTPContentTypes := []string{} + + // set Content-Type header + localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes) + if localVarHTTPContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHTTPContentType + } + + // to determine the Accept header + localVarHTTPHeaderAccepts := []string{} + + // set Accept header + localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) + if localVarHTTPHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept + } + if r.ctx != nil { + // API Key Authentication + if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { + if apiKey, ok := auth["Bearer"]; ok { + var key string + if apiKey.Prefix != "" { + key = apiKey.Prefix + " " + apiKey.Key + } else { + key = apiKey.Key + } + localVarHeaderParams["Authorization"] = key + } + } + } + req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles) + if err != nil { + return nil, err + } + + localVarHTTPResponse, err := a.client.callAPI(req) + if err != nil || localVarHTTPResponse == nil { + return localVarHTTPResponse, err + } + + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) + localVarHTTPResponse.Body.Close() + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) + if err != nil { + return localVarHTTPResponse, err + } + + if localVarHTTPResponse.StatusCode >= 300 { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: localVarHTTPResponse.Status, + } + return localVarHTTPResponse, newErr + } + + return localVarHTTPResponse, nil +} + +type ApiSetDefaultTargetRequest struct { + ctx context.Context + ApiService *TargetAPIService + targetId string +} + +func (r ApiSetDefaultTargetRequest) Execute() (*http.Response, error) { + return r.ApiService.SetDefaultTargetExecute(r) +} + +/* +SetDefaultTarget Set target to be used by default + +Set target to be used by default + + @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + @param targetId Target ID or name + @return ApiSetDefaultTargetRequest +*/ +func (a *TargetAPIService) SetDefaultTarget(ctx context.Context, targetId string) ApiSetDefaultTargetRequest { + return ApiSetDefaultTargetRequest{ + ApiService: a, + ctx: ctx, + targetId: targetId, + } +} + +// Execute executes the request +func (a *TargetAPIService) SetDefaultTargetExecute(r ApiSetDefaultTargetRequest) (*http.Response, error) { + var ( + localVarHTTPMethod = http.MethodPatch + localVarPostBody interface{} + formFiles []formFile + ) + + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "TargetAPIService.SetDefaultTarget") + if err != nil { + return nil, &GenericOpenAPIError{error: err.Error()} + } + + localVarPath := localBasePath + "/target/{targetId}/set-default" + localVarPath = strings.Replace(localVarPath, "{"+"targetId"+"}", url.PathEscape(parameterValueToString(r.targetId, "targetId")), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHTTPContentTypes := []string{} + + // set Content-Type header + localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes) + if localVarHTTPContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHTTPContentType + } + + // to determine the Accept header + localVarHTTPHeaderAccepts := []string{} + + // set Accept header + localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) + if localVarHTTPHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept + } + if r.ctx != nil { + // API Key Authentication + if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { + if apiKey, ok := auth["Bearer"]; ok { + var key string + if apiKey.Prefix != "" { + key = apiKey.Prefix + " " + apiKey.Key + } else { + key = apiKey.Key + } + localVarHeaderParams["Authorization"] = key + } + } + } + req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles) + if err != nil { + return nil, err + } + + localVarHTTPResponse, err := a.client.callAPI(req) + if err != nil || localVarHTTPResponse == nil { + return localVarHTTPResponse, err + } + + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) + localVarHTTPResponse.Body.Close() + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) + if err != nil { + return localVarHTTPResponse, err + } + + if localVarHTTPResponse.StatusCode >= 300 { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: localVarHTTPResponse.Status, + } + return localVarHTTPResponse, newErr + } + + return localVarHTTPResponse, nil +} + +type ApiStartTargetRequest struct { + ctx context.Context + ApiService *TargetAPIService + targetId string +} + +func (r ApiStartTargetRequest) Execute() (*http.Response, error) { + return r.ApiService.StartTargetExecute(r) +} + +/* +StartTarget Start target + +Start target + + @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + @param targetId Target ID or Name + @return ApiStartTargetRequest +*/ +func (a *TargetAPIService) StartTarget(ctx context.Context, targetId string) ApiStartTargetRequest { + return ApiStartTargetRequest{ + ApiService: a, + ctx: ctx, + targetId: targetId, + } +} + +// Execute executes the request +func (a *TargetAPIService) StartTargetExecute(r ApiStartTargetRequest) (*http.Response, error) { + var ( + localVarHTTPMethod = http.MethodPost + localVarPostBody interface{} + formFiles []formFile + ) + + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "TargetAPIService.StartTarget") + if err != nil { + return nil, &GenericOpenAPIError{error: err.Error()} + } + + localVarPath := localBasePath + "/target/{targetId}/start" + localVarPath = strings.Replace(localVarPath, "{"+"targetId"+"}", url.PathEscape(parameterValueToString(r.targetId, "targetId")), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHTTPContentTypes := []string{} + + // set Content-Type header + localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes) + if localVarHTTPContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHTTPContentType + } + + // to determine the Accept header + localVarHTTPHeaderAccepts := []string{} + + // set Accept header + localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) + if localVarHTTPHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept + } + if r.ctx != nil { + // API Key Authentication + if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { + if apiKey, ok := auth["Bearer"]; ok { + var key string + if apiKey.Prefix != "" { + key = apiKey.Prefix + " " + apiKey.Key + } else { + key = apiKey.Key + } + localVarHeaderParams["Authorization"] = key + } + } + } + req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles) + if err != nil { + return nil, err + } + + localVarHTTPResponse, err := a.client.callAPI(req) + if err != nil || localVarHTTPResponse == nil { + return localVarHTTPResponse, err + } + + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) + localVarHTTPResponse.Body.Close() + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) + if err != nil { + return localVarHTTPResponse, err + } + + if localVarHTTPResponse.StatusCode >= 300 { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: localVarHTTPResponse.Status, + } + return localVarHTTPResponse, newErr + } + + return localVarHTTPResponse, nil +} + +type ApiStopTargetRequest struct { + ctx context.Context + ApiService *TargetAPIService + targetId string +} + +func (r ApiStopTargetRequest) Execute() (*http.Response, error) { + return r.ApiService.StopTargetExecute(r) +} + +/* +StopTarget Stop target + +Stop target + + @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + @param targetId Target ID or Name + @return ApiStopTargetRequest +*/ +func (a *TargetAPIService) StopTarget(ctx context.Context, targetId string) ApiStopTargetRequest { + return ApiStopTargetRequest{ + ApiService: a, + ctx: ctx, + targetId: targetId, + } +} + +// Execute executes the request +func (a *TargetAPIService) StopTargetExecute(r ApiStopTargetRequest) (*http.Response, error) { + var ( + localVarHTTPMethod = http.MethodPost + localVarPostBody interface{} + formFiles []formFile + ) + + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "TargetAPIService.StopTarget") + if err != nil { + return nil, &GenericOpenAPIError{error: err.Error()} + } + + localVarPath := localBasePath + "/target/{targetId}/stop" + localVarPath = strings.Replace(localVarPath, "{"+"targetId"+"}", url.PathEscape(parameterValueToString(r.targetId, "targetId")), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHTTPContentTypes := []string{} + + // set Content-Type header + localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes) + if localVarHTTPContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHTTPContentType + } + + // to determine the Accept header + localVarHTTPHeaderAccepts := []string{} + + // set Accept header + localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) + if localVarHTTPHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept + } + if r.ctx != nil { + // API Key Authentication + if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { + if apiKey, ok := auth["Bearer"]; ok { + var key string + if apiKey.Prefix != "" { + key = apiKey.Prefix + " " + apiKey.Key + } else { + key = apiKey.Key + } + localVarHeaderParams["Authorization"] = key + } + } + } + req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles) + if err != nil { + return nil, err + } + + localVarHTTPResponse, err := a.client.callAPI(req) + if err != nil || localVarHTTPResponse == nil { + return localVarHTTPResponse, err + } + + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) + localVarHTTPResponse.Body.Close() + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) + if err != nil { + return localVarHTTPResponse, err + } + + if localVarHTTPResponse.StatusCode >= 300 { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: localVarHTTPResponse.Status, + } + return localVarHTTPResponse, newErr + } + + return localVarHTTPResponse, nil +} + +type ApiUpdateTargetMetadataRequest struct { + ctx context.Context + ApiService *TargetAPIService + targetId string + targetMetadata *UpdateTargetMetadataDTO +} + +// Target Metadata +func (r ApiUpdateTargetMetadataRequest) TargetMetadata(targetMetadata UpdateTargetMetadataDTO) ApiUpdateTargetMetadataRequest { + r.targetMetadata = &targetMetadata + return r +} + +func (r ApiUpdateTargetMetadataRequest) Execute() (*http.Response, error) { + return r.ApiService.UpdateTargetMetadataExecute(r) +} + +/* +UpdateTargetMetadata Update target metadata + +Update target metadata + + @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + @param targetId Target ID + @return ApiUpdateTargetMetadataRequest +*/ +func (a *TargetAPIService) UpdateTargetMetadata(ctx context.Context, targetId string) ApiUpdateTargetMetadataRequest { + return ApiUpdateTargetMetadataRequest{ + ApiService: a, + ctx: ctx, + targetId: targetId, + } +} + +// Execute executes the request +func (a *TargetAPIService) UpdateTargetMetadataExecute(r ApiUpdateTargetMetadataRequest) (*http.Response, error) { + var ( + localVarHTTPMethod = http.MethodPost + localVarPostBody interface{} + formFiles []formFile + ) + + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "TargetAPIService.UpdateTargetMetadata") + if err != nil { + return nil, &GenericOpenAPIError{error: err.Error()} + } + + localVarPath := localBasePath + "/target/{targetId}/metadata" + localVarPath = strings.Replace(localVarPath, "{"+"targetId"+"}", url.PathEscape(parameterValueToString(r.targetId, "targetId")), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + if r.targetMetadata == nil { + return nil, reportError("targetMetadata is required and must be specified") + } + + // to determine the Content-Type header + localVarHTTPContentTypes := []string{} + + // set Content-Type header + localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes) + if localVarHTTPContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHTTPContentType + } + + // to determine the Accept header + localVarHTTPHeaderAccepts := []string{} // set Accept header localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) @@ -419,7 +1239,125 @@ func (a *TargetAPIService) SetTargetExecute(r ApiSetTargetRequest) (*http.Respon localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept } // body params - localVarPostBody = r.target + localVarPostBody = r.targetMetadata + if r.ctx != nil { + // API Key Authentication + if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { + if apiKey, ok := auth["Bearer"]; ok { + var key string + if apiKey.Prefix != "" { + key = apiKey.Prefix + " " + apiKey.Key + } else { + key = apiKey.Key + } + localVarHeaderParams["Authorization"] = key + } + } + } + req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles) + if err != nil { + return nil, err + } + + localVarHTTPResponse, err := a.client.callAPI(req) + if err != nil || localVarHTTPResponse == nil { + return localVarHTTPResponse, err + } + + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) + localVarHTTPResponse.Body.Close() + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) + if err != nil { + return localVarHTTPResponse, err + } + + if localVarHTTPResponse.StatusCode >= 300 { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: localVarHTTPResponse.Status, + } + return localVarHTTPResponse, newErr + } + + return localVarHTTPResponse, nil +} + +type ApiUpdateTargetProviderMetadataRequest struct { + ctx context.Context + ApiService *TargetAPIService + targetId string + metadata *UpdateTargetProviderMetadataDTO +} + +// Provider metadata +func (r ApiUpdateTargetProviderMetadataRequest) Metadata(metadata UpdateTargetProviderMetadataDTO) ApiUpdateTargetProviderMetadataRequest { + r.metadata = &metadata + return r +} + +func (r ApiUpdateTargetProviderMetadataRequest) Execute() (*http.Response, error) { + return r.ApiService.UpdateTargetProviderMetadataExecute(r) +} + +/* +UpdateTargetProviderMetadata Update target provider metadata + +Update target provider metadata + + @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + @param targetId Target ID + @return ApiUpdateTargetProviderMetadataRequest +*/ +func (a *TargetAPIService) UpdateTargetProviderMetadata(ctx context.Context, targetId string) ApiUpdateTargetProviderMetadataRequest { + return ApiUpdateTargetProviderMetadataRequest{ + ApiService: a, + ctx: ctx, + targetId: targetId, + } +} + +// Execute executes the request +func (a *TargetAPIService) UpdateTargetProviderMetadataExecute(r ApiUpdateTargetProviderMetadataRequest) (*http.Response, error) { + var ( + localVarHTTPMethod = http.MethodPost + localVarPostBody interface{} + formFiles []formFile + ) + + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "TargetAPIService.UpdateTargetProviderMetadata") + if err != nil { + return nil, &GenericOpenAPIError{error: err.Error()} + } + + localVarPath := localBasePath + "/target/{targetId}/provider-metadata" + localVarPath = strings.Replace(localVarPath, "{"+"targetId"+"}", url.PathEscape(parameterValueToString(r.targetId, "targetId")), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + if r.metadata == nil { + return nil, reportError("metadata is required and must be specified") + } + + // to determine the Content-Type header + localVarHTTPContentTypes := []string{} + + // set Content-Type header + localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes) + if localVarHTTPContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHTTPContentType + } + + // to determine the Accept header + localVarHTTPHeaderAccepts := []string{} + + // set Accept header + localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) + if localVarHTTPHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept + } + // body params + localVarPostBody = r.metadata if r.ctx != nil { // API Key Authentication if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { diff --git a/pkg/apiclient/api_target_config.go b/pkg/apiclient/api_target_config.go new file mode 100644 index 0000000000..5b66eca67c --- /dev/null +++ b/pkg/apiclient/api_target_config.go @@ -0,0 +1,389 @@ +/* +Daytona Server API + +Daytona Server API + +API version: v0.0.0-dev +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package apiclient + +import ( + "bytes" + "context" + "io" + "net/http" + "net/url" + "strings" +) + +// TargetConfigAPIService TargetConfigAPI service +type TargetConfigAPIService service + +type ApiCreateTargetConfigRequest struct { + ctx context.Context + ApiService *TargetConfigAPIService + targetConfig *CreateTargetConfigDTO + showOptions *bool +} + +// Target config to create +func (r ApiCreateTargetConfigRequest) TargetConfig(targetConfig CreateTargetConfigDTO) ApiCreateTargetConfigRequest { + r.targetConfig = &targetConfig + return r +} + +// Show target config options +func (r ApiCreateTargetConfigRequest) ShowOptions(showOptions bool) ApiCreateTargetConfigRequest { + r.showOptions = &showOptions + return r +} + +func (r ApiCreateTargetConfigRequest) Execute() (*TargetConfig, *http.Response, error) { + return r.ApiService.CreateTargetConfigExecute(r) +} + +/* +CreateTargetConfig Create a target config + +Create a target config + + @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + @return ApiCreateTargetConfigRequest +*/ +func (a *TargetConfigAPIService) CreateTargetConfig(ctx context.Context) ApiCreateTargetConfigRequest { + return ApiCreateTargetConfigRequest{ + ApiService: a, + ctx: ctx, + } +} + +// Execute executes the request +// +// @return TargetConfig +func (a *TargetConfigAPIService) CreateTargetConfigExecute(r ApiCreateTargetConfigRequest) (*TargetConfig, *http.Response, error) { + var ( + localVarHTTPMethod = http.MethodPost + localVarPostBody interface{} + formFiles []formFile + localVarReturnValue *TargetConfig + ) + + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "TargetConfigAPIService.CreateTargetConfig") + if err != nil { + return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} + } + + localVarPath := localBasePath + "/target-config" + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + if r.targetConfig == nil { + return localVarReturnValue, nil, reportError("targetConfig is required and must be specified") + } + + if r.showOptions != nil { + parameterAddToHeaderOrQuery(localVarQueryParams, "showOptions", r.showOptions, "") + } + // to determine the Content-Type header + localVarHTTPContentTypes := []string{} + + // set Content-Type header + localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes) + if localVarHTTPContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHTTPContentType + } + + // to determine the Accept header + localVarHTTPHeaderAccepts := []string{"*/*"} + + // set Accept header + localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) + if localVarHTTPHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept + } + // body params + localVarPostBody = r.targetConfig + if r.ctx != nil { + // API Key Authentication + if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { + if apiKey, ok := auth["Bearer"]; ok { + var key string + if apiKey.Prefix != "" { + key = apiKey.Prefix + " " + apiKey.Key + } else { + key = apiKey.Key + } + localVarHeaderParams["Authorization"] = key + } + } + } + req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHTTPResponse, err := a.client.callAPI(req) + if err != nil || localVarHTTPResponse == nil { + return localVarReturnValue, localVarHTTPResponse, err + } + + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) + localVarHTTPResponse.Body.Close() + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) + if err != nil { + return localVarReturnValue, localVarHTTPResponse, err + } + + if localVarHTTPResponse.StatusCode >= 300 { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: localVarHTTPResponse.Status, + } + return localVarReturnValue, localVarHTTPResponse, newErr + } + + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: err.Error(), + } + return localVarReturnValue, localVarHTTPResponse, newErr + } + + return localVarReturnValue, localVarHTTPResponse, nil +} + +type ApiDeleteTargetConfigRequest struct { + ctx context.Context + ApiService *TargetConfigAPIService + configId string +} + +func (r ApiDeleteTargetConfigRequest) Execute() (*http.Response, error) { + return r.ApiService.DeleteTargetConfigExecute(r) +} + +/* +DeleteTargetConfig Delete a target config + +Delete a target config + + @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + @param configId Target Config Id + @return ApiDeleteTargetConfigRequest +*/ +func (a *TargetConfigAPIService) DeleteTargetConfig(ctx context.Context, configId string) ApiDeleteTargetConfigRequest { + return ApiDeleteTargetConfigRequest{ + ApiService: a, + ctx: ctx, + configId: configId, + } +} + +// Execute executes the request +func (a *TargetConfigAPIService) DeleteTargetConfigExecute(r ApiDeleteTargetConfigRequest) (*http.Response, error) { + var ( + localVarHTTPMethod = http.MethodDelete + localVarPostBody interface{} + formFiles []formFile + ) + + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "TargetConfigAPIService.DeleteTargetConfig") + if err != nil { + return nil, &GenericOpenAPIError{error: err.Error()} + } + + localVarPath := localBasePath + "/target-config/{configId}" + localVarPath = strings.Replace(localVarPath, "{"+"configId"+"}", url.PathEscape(parameterValueToString(r.configId, "configId")), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHTTPContentTypes := []string{} + + // set Content-Type header + localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes) + if localVarHTTPContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHTTPContentType + } + + // to determine the Accept header + localVarHTTPHeaderAccepts := []string{} + + // set Accept header + localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) + if localVarHTTPHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept + } + if r.ctx != nil { + // API Key Authentication + if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { + if apiKey, ok := auth["Bearer"]; ok { + var key string + if apiKey.Prefix != "" { + key = apiKey.Prefix + " " + apiKey.Key + } else { + key = apiKey.Key + } + localVarHeaderParams["Authorization"] = key + } + } + } + req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles) + if err != nil { + return nil, err + } + + localVarHTTPResponse, err := a.client.callAPI(req) + if err != nil || localVarHTTPResponse == nil { + return localVarHTTPResponse, err + } + + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) + localVarHTTPResponse.Body.Close() + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) + if err != nil { + return localVarHTTPResponse, err + } + + if localVarHTTPResponse.StatusCode >= 300 { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: localVarHTTPResponse.Status, + } + return localVarHTTPResponse, newErr + } + + return localVarHTTPResponse, nil +} + +type ApiListTargetConfigsRequest struct { + ctx context.Context + ApiService *TargetConfigAPIService + showOptions *bool +} + +// Show target config options +func (r ApiListTargetConfigsRequest) ShowOptions(showOptions bool) ApiListTargetConfigsRequest { + r.showOptions = &showOptions + return r +} + +func (r ApiListTargetConfigsRequest) Execute() ([]TargetConfig, *http.Response, error) { + return r.ApiService.ListTargetConfigsExecute(r) +} + +/* +ListTargetConfigs List target configs + +List target configs + + @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + @return ApiListTargetConfigsRequest +*/ +func (a *TargetConfigAPIService) ListTargetConfigs(ctx context.Context) ApiListTargetConfigsRequest { + return ApiListTargetConfigsRequest{ + ApiService: a, + ctx: ctx, + } +} + +// Execute executes the request +// +// @return []TargetConfig +func (a *TargetConfigAPIService) ListTargetConfigsExecute(r ApiListTargetConfigsRequest) ([]TargetConfig, *http.Response, error) { + var ( + localVarHTTPMethod = http.MethodGet + localVarPostBody interface{} + formFiles []formFile + localVarReturnValue []TargetConfig + ) + + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "TargetConfigAPIService.ListTargetConfigs") + if err != nil { + return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} + } + + localVarPath := localBasePath + "/target-config" + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + if r.showOptions != nil { + parameterAddToHeaderOrQuery(localVarQueryParams, "showOptions", r.showOptions, "") + } + // to determine the Content-Type header + localVarHTTPContentTypes := []string{} + + // set Content-Type header + localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes) + if localVarHTTPContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHTTPContentType + } + + // to determine the Accept header + localVarHTTPHeaderAccepts := []string{"application/json"} + + // set Accept header + localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) + if localVarHTTPHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept + } + if r.ctx != nil { + // API Key Authentication + if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { + if apiKey, ok := auth["Bearer"]; ok { + var key string + if apiKey.Prefix != "" { + key = apiKey.Prefix + " " + apiKey.Key + } else { + key = apiKey.Key + } + localVarHeaderParams["Authorization"] = key + } + } + } + req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHTTPResponse, err := a.client.callAPI(req) + if err != nil || localVarHTTPResponse == nil { + return localVarReturnValue, localVarHTTPResponse, err + } + + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) + localVarHTTPResponse.Body.Close() + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) + if err != nil { + return localVarReturnValue, localVarHTTPResponse, err + } + + if localVarHTTPResponse.StatusCode >= 300 { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: localVarHTTPResponse.Status, + } + return localVarReturnValue, localVarHTTPResponse, newErr + } + + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: err.Error(), + } + return localVarReturnValue, localVarHTTPResponse, newErr + } + + return localVarReturnValue, localVarHTTPResponse, nil +} diff --git a/pkg/apiclient/api_workspace.go b/pkg/apiclient/api_workspace.go index a202e49d42..b18d640e69 100644 --- a/pkg/apiclient/api_workspace.go +++ b/pkg/apiclient/api_workspace.go @@ -34,7 +34,7 @@ func (r ApiCreateWorkspaceRequest) Workspace(workspace CreateWorkspaceDTO) ApiCr return r } -func (r ApiCreateWorkspaceRequest) Execute() (*Workspace, *http.Response, error) { +func (r ApiCreateWorkspaceRequest) Execute() (*WorkspaceDTO, *http.Response, error) { return r.ApiService.CreateWorkspaceExecute(r) } @@ -55,13 +55,13 @@ func (a *WorkspaceAPIService) CreateWorkspace(ctx context.Context) ApiCreateWork // Execute executes the request // -// @return Workspace -func (a *WorkspaceAPIService) CreateWorkspaceExecute(r ApiCreateWorkspaceRequest) (*Workspace, *http.Response, error) { +// @return WorkspaceDTO +func (a *WorkspaceAPIService) CreateWorkspaceExecute(r ApiCreateWorkspaceRequest) (*WorkspaceDTO, *http.Response, error) { var ( localVarHTTPMethod = http.MethodPost localVarPostBody interface{} formFiles []formFile - localVarReturnValue *Workspace + localVarReturnValue *WorkspaceDTO ) localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "WorkspaceAPIService.CreateWorkspace") @@ -148,34 +148,143 @@ func (a *WorkspaceAPIService) CreateWorkspaceExecute(r ApiCreateWorkspaceRequest return localVarReturnValue, localVarHTTPResponse, nil } -type ApiGetWorkspaceRequest struct { +type ApiDeleteWorkspaceRequest struct { ctx context.Context ApiService *WorkspaceAPIService workspaceId string - verbose *bool + force *bool } -// Verbose -func (r ApiGetWorkspaceRequest) Verbose(verbose bool) ApiGetWorkspaceRequest { - r.verbose = &verbose +// Force +func (r ApiDeleteWorkspaceRequest) Force(force bool) ApiDeleteWorkspaceRequest { + r.force = &force return r } -func (r ApiGetWorkspaceRequest) Execute() (*WorkspaceDTO, *http.Response, error) { - return r.ApiService.GetWorkspaceExecute(r) +func (r ApiDeleteWorkspaceRequest) Execute() (*http.Response, error) { + return r.ApiService.DeleteWorkspaceExecute(r) +} + +/* +DeleteWorkspace Delete workspace + +Delete workspace + + @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + @param workspaceId Workspace ID + @return ApiDeleteWorkspaceRequest +*/ +func (a *WorkspaceAPIService) DeleteWorkspace(ctx context.Context, workspaceId string) ApiDeleteWorkspaceRequest { + return ApiDeleteWorkspaceRequest{ + ApiService: a, + ctx: ctx, + workspaceId: workspaceId, + } +} + +// Execute executes the request +func (a *WorkspaceAPIService) DeleteWorkspaceExecute(r ApiDeleteWorkspaceRequest) (*http.Response, error) { + var ( + localVarHTTPMethod = http.MethodDelete + localVarPostBody interface{} + formFiles []formFile + ) + + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "WorkspaceAPIService.DeleteWorkspace") + if err != nil { + return nil, &GenericOpenAPIError{error: err.Error()} + } + + localVarPath := localBasePath + "/workspace/{workspaceId}" + localVarPath = strings.Replace(localVarPath, "{"+"workspaceId"+"}", url.PathEscape(parameterValueToString(r.workspaceId, "workspaceId")), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + if r.force != nil { + parameterAddToHeaderOrQuery(localVarQueryParams, "force", r.force, "") + } + // to determine the Content-Type header + localVarHTTPContentTypes := []string{} + + // set Content-Type header + localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes) + if localVarHTTPContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHTTPContentType + } + + // to determine the Accept header + localVarHTTPHeaderAccepts := []string{} + + // set Accept header + localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) + if localVarHTTPHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept + } + if r.ctx != nil { + // API Key Authentication + if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { + if apiKey, ok := auth["Bearer"]; ok { + var key string + if apiKey.Prefix != "" { + key = apiKey.Prefix + " " + apiKey.Key + } else { + key = apiKey.Key + } + localVarHeaderParams["Authorization"] = key + } + } + } + req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles) + if err != nil { + return nil, err + } + + localVarHTTPResponse, err := a.client.callAPI(req) + if err != nil || localVarHTTPResponse == nil { + return localVarHTTPResponse, err + } + + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) + localVarHTTPResponse.Body.Close() + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) + if err != nil { + return localVarHTTPResponse, err + } + + if localVarHTTPResponse.StatusCode >= 300 { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: localVarHTTPResponse.Status, + } + return localVarHTTPResponse, newErr + } + + return localVarHTTPResponse, nil +} + +type ApiFindWorkspaceRequest struct { + ctx context.Context + ApiService *WorkspaceAPIService + workspaceId string +} + +func (r ApiFindWorkspaceRequest) Execute() (*WorkspaceDTO, *http.Response, error) { + return r.ApiService.FindWorkspaceExecute(r) } /* -GetWorkspace Get workspace info +FindWorkspace Find workspace -Get workspace info +Find workspace @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @param workspaceId Workspace ID or Name - @return ApiGetWorkspaceRequest + @return ApiFindWorkspaceRequest */ -func (a *WorkspaceAPIService) GetWorkspace(ctx context.Context, workspaceId string) ApiGetWorkspaceRequest { - return ApiGetWorkspaceRequest{ +func (a *WorkspaceAPIService) FindWorkspace(ctx context.Context, workspaceId string) ApiFindWorkspaceRequest { + return ApiFindWorkspaceRequest{ ApiService: a, ctx: ctx, workspaceId: workspaceId, @@ -185,7 +294,7 @@ func (a *WorkspaceAPIService) GetWorkspace(ctx context.Context, workspaceId stri // Execute executes the request // // @return WorkspaceDTO -func (a *WorkspaceAPIService) GetWorkspaceExecute(r ApiGetWorkspaceRequest) (*WorkspaceDTO, *http.Response, error) { +func (a *WorkspaceAPIService) FindWorkspaceExecute(r ApiFindWorkspaceRequest) (*WorkspaceDTO, *http.Response, error) { var ( localVarHTTPMethod = http.MethodGet localVarPostBody interface{} @@ -193,7 +302,7 @@ func (a *WorkspaceAPIService) GetWorkspaceExecute(r ApiGetWorkspaceRequest) (*Wo localVarReturnValue *WorkspaceDTO ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "WorkspaceAPIService.GetWorkspace") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "WorkspaceAPIService.FindWorkspace") if err != nil { return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } @@ -205,9 +314,124 @@ func (a *WorkspaceAPIService) GetWorkspaceExecute(r ApiGetWorkspaceRequest) (*Wo localVarQueryParams := url.Values{} localVarFormParams := url.Values{} - if r.verbose != nil { - parameterAddToHeaderOrQuery(localVarQueryParams, "verbose", r.verbose, "") + // to determine the Content-Type header + localVarHTTPContentTypes := []string{} + + // set Content-Type header + localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes) + if localVarHTTPContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHTTPContentType + } + + // to determine the Accept header + localVarHTTPHeaderAccepts := []string{"application/json"} + + // set Accept header + localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) + if localVarHTTPHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept + } + if r.ctx != nil { + // API Key Authentication + if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { + if apiKey, ok := auth["Bearer"]; ok { + var key string + if apiKey.Prefix != "" { + key = apiKey.Prefix + " " + apiKey.Key + } else { + key = apiKey.Key + } + localVarHeaderParams["Authorization"] = key + } + } + } + req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHTTPResponse, err := a.client.callAPI(req) + if err != nil || localVarHTTPResponse == nil { + return localVarReturnValue, localVarHTTPResponse, err + } + + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) + localVarHTTPResponse.Body.Close() + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) + if err != nil { + return localVarReturnValue, localVarHTTPResponse, err + } + + if localVarHTTPResponse.StatusCode >= 300 { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: localVarHTTPResponse.Status, + } + return localVarReturnValue, localVarHTTPResponse, newErr + } + + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: err.Error(), + } + return localVarReturnValue, localVarHTTPResponse, newErr + } + + return localVarReturnValue, localVarHTTPResponse, nil +} + +type ApiGetWorkspaceStateRequest struct { + ctx context.Context + ApiService *WorkspaceAPIService + workspaceId string +} + +func (r ApiGetWorkspaceStateRequest) Execute() (*ResourceState, *http.Response, error) { + return r.ApiService.GetWorkspaceStateExecute(r) +} + +/* +GetWorkspaceState Get workspace state + +Get workspace state + + @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + @param workspaceId Workspace ID or Name + @return ApiGetWorkspaceStateRequest +*/ +func (a *WorkspaceAPIService) GetWorkspaceState(ctx context.Context, workspaceId string) ApiGetWorkspaceStateRequest { + return ApiGetWorkspaceStateRequest{ + ApiService: a, + ctx: ctx, + workspaceId: workspaceId, + } +} + +// Execute executes the request +// +// @return ResourceState +func (a *WorkspaceAPIService) GetWorkspaceStateExecute(r ApiGetWorkspaceStateRequest) (*ResourceState, *http.Response, error) { + var ( + localVarHTTPMethod = http.MethodGet + localVarPostBody interface{} + formFiles []formFile + localVarReturnValue *ResourceState + ) + + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "WorkspaceAPIService.GetWorkspaceState") + if err != nil { + return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } + + localVarPath := localBasePath + "/workspace/{workspaceId}/state" + localVarPath = strings.Replace(localVarPath, "{"+"workspaceId"+"}", url.PathEscape(parameterValueToString(r.workspaceId, "workspaceId")), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + // to determine the Content-Type header localVarHTTPContentTypes := []string{} @@ -279,12 +503,12 @@ func (a *WorkspaceAPIService) GetWorkspaceExecute(r ApiGetWorkspaceRequest) (*Wo type ApiListWorkspacesRequest struct { ctx context.Context ApiService *WorkspaceAPIService - verbose *bool + labels *string } -// Verbose -func (r ApiListWorkspacesRequest) Verbose(verbose bool) ApiListWorkspacesRequest { - r.verbose = &verbose +// JSON encoded labels +func (r ApiListWorkspacesRequest) Labels(labels string) ApiListWorkspacesRequest { + r.labels = &labels return r } @@ -329,8 +553,8 @@ func (a *WorkspaceAPIService) ListWorkspacesExecute(r ApiListWorkspacesRequest) localVarQueryParams := url.Values{} localVarFormParams := url.Values{} - if r.verbose != nil { - parameterAddToHeaderOrQuery(localVarQueryParams, "verbose", r.verbose, "") + if r.labels != nil { + parameterAddToHeaderOrQuery(localVarQueryParams, "labels", r.labels, "") } // to determine the Content-Type header localVarHTTPContentTypes := []string{} @@ -400,34 +624,27 @@ func (a *WorkspaceAPIService) ListWorkspacesExecute(r ApiListWorkspacesRequest) return localVarReturnValue, localVarHTTPResponse, nil } -type ApiRemoveWorkspaceRequest struct { +type ApiRestartWorkspaceRequest struct { ctx context.Context ApiService *WorkspaceAPIService workspaceId string - force *bool -} - -// Force -func (r ApiRemoveWorkspaceRequest) Force(force bool) ApiRemoveWorkspaceRequest { - r.force = &force - return r } -func (r ApiRemoveWorkspaceRequest) Execute() (*http.Response, error) { - return r.ApiService.RemoveWorkspaceExecute(r) +func (r ApiRestartWorkspaceRequest) Execute() (*http.Response, error) { + return r.ApiService.RestartWorkspaceExecute(r) } /* -RemoveWorkspace Remove workspace +RestartWorkspace Restart workspace -Remove workspace +Restart workspace @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). - @param workspaceId Workspace ID - @return ApiRemoveWorkspaceRequest + @param workspaceId Workspace ID or Name + @return ApiRestartWorkspaceRequest */ -func (a *WorkspaceAPIService) RemoveWorkspace(ctx context.Context, workspaceId string) ApiRemoveWorkspaceRequest { - return ApiRemoveWorkspaceRequest{ +func (a *WorkspaceAPIService) RestartWorkspace(ctx context.Context, workspaceId string) ApiRestartWorkspaceRequest { + return ApiRestartWorkspaceRequest{ ApiService: a, ctx: ctx, workspaceId: workspaceId, @@ -435,28 +652,25 @@ func (a *WorkspaceAPIService) RemoveWorkspace(ctx context.Context, workspaceId s } // Execute executes the request -func (a *WorkspaceAPIService) RemoveWorkspaceExecute(r ApiRemoveWorkspaceRequest) (*http.Response, error) { +func (a *WorkspaceAPIService) RestartWorkspaceExecute(r ApiRestartWorkspaceRequest) (*http.Response, error) { var ( - localVarHTTPMethod = http.MethodDelete + localVarHTTPMethod = http.MethodPost localVarPostBody interface{} formFiles []formFile ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "WorkspaceAPIService.RemoveWorkspace") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "WorkspaceAPIService.RestartWorkspace") if err != nil { return nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/workspace/{workspaceId}" + localVarPath := localBasePath + "/workspace/{workspaceId}/restart" localVarPath = strings.Replace(localVarPath, "{"+"workspaceId"+"}", url.PathEscape(parameterValueToString(r.workspaceId, "workspaceId")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} localVarFormParams := url.Values{} - if r.force != nil { - parameterAddToHeaderOrQuery(localVarQueryParams, "force", r.force, "") - } // to determine the Content-Type header localVarHTTPContentTypes := []string{} @@ -516,66 +730,52 @@ func (a *WorkspaceAPIService) RemoveWorkspaceExecute(r ApiRemoveWorkspaceRequest return localVarHTTPResponse, nil } -type ApiSetProjectStateRequest struct { +type ApiStartWorkspaceRequest struct { ctx context.Context ApiService *WorkspaceAPIService workspaceId string - projectId string - setState *SetProjectState } -// Set State -func (r ApiSetProjectStateRequest) SetState(setState SetProjectState) ApiSetProjectStateRequest { - r.setState = &setState - return r -} - -func (r ApiSetProjectStateRequest) Execute() (*http.Response, error) { - return r.ApiService.SetProjectStateExecute(r) +func (r ApiStartWorkspaceRequest) Execute() (*http.Response, error) { + return r.ApiService.StartWorkspaceExecute(r) } /* -SetProjectState Set project state +StartWorkspace Start workspace -Set project state +Start workspace @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @param workspaceId Workspace ID or Name - @param projectId Project ID - @return ApiSetProjectStateRequest + @return ApiStartWorkspaceRequest */ -func (a *WorkspaceAPIService) SetProjectState(ctx context.Context, workspaceId string, projectId string) ApiSetProjectStateRequest { - return ApiSetProjectStateRequest{ +func (a *WorkspaceAPIService) StartWorkspace(ctx context.Context, workspaceId string) ApiStartWorkspaceRequest { + return ApiStartWorkspaceRequest{ ApiService: a, ctx: ctx, workspaceId: workspaceId, - projectId: projectId, } } // Execute executes the request -func (a *WorkspaceAPIService) SetProjectStateExecute(r ApiSetProjectStateRequest) (*http.Response, error) { +func (a *WorkspaceAPIService) StartWorkspaceExecute(r ApiStartWorkspaceRequest) (*http.Response, error) { var ( localVarHTTPMethod = http.MethodPost localVarPostBody interface{} formFiles []formFile ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "WorkspaceAPIService.SetProjectState") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "WorkspaceAPIService.StartWorkspace") if err != nil { return nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/workspace/{workspaceId}/{projectId}/state" + localVarPath := localBasePath + "/workspace/{workspaceId}/start" localVarPath = strings.Replace(localVarPath, "{"+"workspaceId"+"}", url.PathEscape(parameterValueToString(r.workspaceId, "workspaceId")), -1) - localVarPath = strings.Replace(localVarPath, "{"+"projectId"+"}", url.PathEscape(parameterValueToString(r.projectId, "projectId")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} localVarFormParams := url.Values{} - if r.setState == nil { - return nil, reportError("setState is required and must be specified") - } // to determine the Content-Type header localVarHTTPContentTypes := []string{} @@ -594,8 +794,6 @@ func (a *WorkspaceAPIService) SetProjectStateExecute(r ApiSetProjectStateRequest if localVarHTTPHeaderAccept != "" { localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept } - // body params - localVarPostBody = r.setState if r.ctx != nil { // API Key Authentication if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { @@ -638,52 +836,48 @@ func (a *WorkspaceAPIService) SetProjectStateExecute(r ApiSetProjectStateRequest return localVarHTTPResponse, nil } -type ApiStartProjectRequest struct { +type ApiStopWorkspaceRequest struct { ctx context.Context ApiService *WorkspaceAPIService workspaceId string - projectId string } -func (r ApiStartProjectRequest) Execute() (*http.Response, error) { - return r.ApiService.StartProjectExecute(r) +func (r ApiStopWorkspaceRequest) Execute() (*http.Response, error) { + return r.ApiService.StopWorkspaceExecute(r) } /* -StartProject Start project +StopWorkspace Stop workspace -Start project +Stop workspace @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @param workspaceId Workspace ID or Name - @param projectId Project ID - @return ApiStartProjectRequest + @return ApiStopWorkspaceRequest */ -func (a *WorkspaceAPIService) StartProject(ctx context.Context, workspaceId string, projectId string) ApiStartProjectRequest { - return ApiStartProjectRequest{ +func (a *WorkspaceAPIService) StopWorkspace(ctx context.Context, workspaceId string) ApiStopWorkspaceRequest { + return ApiStopWorkspaceRequest{ ApiService: a, ctx: ctx, workspaceId: workspaceId, - projectId: projectId, } } // Execute executes the request -func (a *WorkspaceAPIService) StartProjectExecute(r ApiStartProjectRequest) (*http.Response, error) { +func (a *WorkspaceAPIService) StopWorkspaceExecute(r ApiStopWorkspaceRequest) (*http.Response, error) { var ( localVarHTTPMethod = http.MethodPost localVarPostBody interface{} formFiles []formFile ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "WorkspaceAPIService.StartProject") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "WorkspaceAPIService.StopWorkspace") if err != nil { return nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/workspace/{workspaceId}/{projectId}/start" + localVarPath := localBasePath + "/workspace/{workspaceId}/stop" localVarPath = strings.Replace(localVarPath, "{"+"workspaceId"+"}", url.PathEscape(parameterValueToString(r.workspaceId, "workspaceId")), -1) - localVarPath = strings.Replace(localVarPath, "{"+"projectId"+"}", url.PathEscape(parameterValueToString(r.projectId, "projectId")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -748,27 +942,34 @@ func (a *WorkspaceAPIService) StartProjectExecute(r ApiStartProjectRequest) (*ht return localVarHTTPResponse, nil } -type ApiStartWorkspaceRequest struct { +type ApiUpdateWorkspaceLabelsRequest struct { ctx context.Context ApiService *WorkspaceAPIService workspaceId string + labels *map[string]string } -func (r ApiStartWorkspaceRequest) Execute() (*http.Response, error) { - return r.ApiService.StartWorkspaceExecute(r) +// Labels +func (r ApiUpdateWorkspaceLabelsRequest) Labels(labels map[string]string) ApiUpdateWorkspaceLabelsRequest { + r.labels = &labels + return r +} + +func (r ApiUpdateWorkspaceLabelsRequest) Execute() (*WorkspaceDTO, *http.Response, error) { + return r.ApiService.UpdateWorkspaceLabelsExecute(r) } /* -StartWorkspace Start workspace +UpdateWorkspaceLabels Update workspace labels -Start workspace +Update workspace labels @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @param workspaceId Workspace ID or Name - @return ApiStartWorkspaceRequest + @return ApiUpdateWorkspaceLabelsRequest */ -func (a *WorkspaceAPIService) StartWorkspace(ctx context.Context, workspaceId string) ApiStartWorkspaceRequest { - return ApiStartWorkspaceRequest{ +func (a *WorkspaceAPIService) UpdateWorkspaceLabels(ctx context.Context, workspaceId string) ApiUpdateWorkspaceLabelsRequest { + return ApiUpdateWorkspaceLabelsRequest{ ApiService: a, ctx: ctx, workspaceId: workspaceId, @@ -776,24 +977,30 @@ func (a *WorkspaceAPIService) StartWorkspace(ctx context.Context, workspaceId st } // Execute executes the request -func (a *WorkspaceAPIService) StartWorkspaceExecute(r ApiStartWorkspaceRequest) (*http.Response, error) { +// +// @return WorkspaceDTO +func (a *WorkspaceAPIService) UpdateWorkspaceLabelsExecute(r ApiUpdateWorkspaceLabelsRequest) (*WorkspaceDTO, *http.Response, error) { var ( - localVarHTTPMethod = http.MethodPost - localVarPostBody interface{} - formFiles []formFile + localVarHTTPMethod = http.MethodPost + localVarPostBody interface{} + formFiles []formFile + localVarReturnValue *WorkspaceDTO ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "WorkspaceAPIService.StartWorkspace") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "WorkspaceAPIService.UpdateWorkspaceLabels") if err != nil { - return nil, &GenericOpenAPIError{error: err.Error()} + return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/workspace/{workspaceId}/start" + localVarPath := localBasePath + "/workspace/{workspaceId}/labels" localVarPath = strings.Replace(localVarPath, "{"+"workspaceId"+"}", url.PathEscape(parameterValueToString(r.workspaceId, "workspaceId")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} localVarFormParams := url.Values{} + if r.labels == nil { + return localVarReturnValue, nil, reportError("labels is required and must be specified") + } // to determine the Content-Type header localVarHTTPContentTypes := []string{} @@ -805,13 +1012,15 @@ func (a *WorkspaceAPIService) StartWorkspaceExecute(r ApiStartWorkspaceRequest) } // to determine the Accept header - localVarHTTPHeaderAccepts := []string{} + localVarHTTPHeaderAccepts := []string{"*/*"} // set Accept header localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) if localVarHTTPHeaderAccept != "" { localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept } + // body params + localVarPostBody = r.labels if r.ctx != nil { // API Key Authentication if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { @@ -828,19 +1037,19 @@ func (a *WorkspaceAPIService) StartWorkspaceExecute(r ApiStartWorkspaceRequest) } req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles) if err != nil { - return nil, err + return localVarReturnValue, nil, err } localVarHTTPResponse, err := a.client.callAPI(req) if err != nil || localVarHTTPResponse == nil { - return localVarHTTPResponse, err + return localVarReturnValue, localVarHTTPResponse, err } localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) localVarHTTPResponse.Body.Close() localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) if err != nil { - return localVarHTTPResponse, err + return localVarReturnValue, localVarHTTPResponse, err } if localVarHTTPResponse.StatusCode >= 300 { @@ -848,62 +1057,77 @@ func (a *WorkspaceAPIService) StartWorkspaceExecute(r ApiStartWorkspaceRequest) body: localVarBody, error: localVarHTTPResponse.Status, } - return localVarHTTPResponse, newErr + return localVarReturnValue, localVarHTTPResponse, newErr } - return localVarHTTPResponse, nil + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: err.Error(), + } + return localVarReturnValue, localVarHTTPResponse, newErr + } + + return localVarReturnValue, localVarHTTPResponse, nil } -type ApiStopProjectRequest struct { - ctx context.Context - ApiService *WorkspaceAPIService - workspaceId string - projectId string +type ApiUpdateWorkspaceMetadataRequest struct { + ctx context.Context + ApiService *WorkspaceAPIService + workspaceId string + workspaceMetadata *UpdateWorkspaceMetadataDTO } -func (r ApiStopProjectRequest) Execute() (*http.Response, error) { - return r.ApiService.StopProjectExecute(r) +// Workspace Metadata +func (r ApiUpdateWorkspaceMetadataRequest) WorkspaceMetadata(workspaceMetadata UpdateWorkspaceMetadataDTO) ApiUpdateWorkspaceMetadataRequest { + r.workspaceMetadata = &workspaceMetadata + return r +} + +func (r ApiUpdateWorkspaceMetadataRequest) Execute() (*http.Response, error) { + return r.ApiService.UpdateWorkspaceMetadataExecute(r) } /* -StopProject Stop project +UpdateWorkspaceMetadata Update workspace metadata -Stop project +Update workspace metadata @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). - @param workspaceId Workspace ID or Name - @param projectId Project ID - @return ApiStopProjectRequest + @param workspaceId Workspace ID + @return ApiUpdateWorkspaceMetadataRequest */ -func (a *WorkspaceAPIService) StopProject(ctx context.Context, workspaceId string, projectId string) ApiStopProjectRequest { - return ApiStopProjectRequest{ +func (a *WorkspaceAPIService) UpdateWorkspaceMetadata(ctx context.Context, workspaceId string) ApiUpdateWorkspaceMetadataRequest { + return ApiUpdateWorkspaceMetadataRequest{ ApiService: a, ctx: ctx, workspaceId: workspaceId, - projectId: projectId, } } // Execute executes the request -func (a *WorkspaceAPIService) StopProjectExecute(r ApiStopProjectRequest) (*http.Response, error) { +func (a *WorkspaceAPIService) UpdateWorkspaceMetadataExecute(r ApiUpdateWorkspaceMetadataRequest) (*http.Response, error) { var ( localVarHTTPMethod = http.MethodPost localVarPostBody interface{} formFiles []formFile ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "WorkspaceAPIService.StopProject") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "WorkspaceAPIService.UpdateWorkspaceMetadata") if err != nil { return nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/workspace/{workspaceId}/{projectId}/stop" + localVarPath := localBasePath + "/workspace/{workspaceId}/metadata" localVarPath = strings.Replace(localVarPath, "{"+"workspaceId"+"}", url.PathEscape(parameterValueToString(r.workspaceId, "workspaceId")), -1) - localVarPath = strings.Replace(localVarPath, "{"+"projectId"+"}", url.PathEscape(parameterValueToString(r.projectId, "projectId")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} localVarFormParams := url.Values{} + if r.workspaceMetadata == nil { + return nil, reportError("workspaceMetadata is required and must be specified") + } // to determine the Content-Type header localVarHTTPContentTypes := []string{} @@ -922,6 +1146,8 @@ func (a *WorkspaceAPIService) StopProjectExecute(r ApiStopProjectRequest) (*http if localVarHTTPHeaderAccept != "" { localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept } + // body params + localVarPostBody = r.workspaceMetadata if r.ctx != nil { // API Key Authentication if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { @@ -964,27 +1190,34 @@ func (a *WorkspaceAPIService) StopProjectExecute(r ApiStopProjectRequest) (*http return localVarHTTPResponse, nil } -type ApiStopWorkspaceRequest struct { +type ApiUpdateWorkspaceProviderMetadataRequest struct { ctx context.Context ApiService *WorkspaceAPIService workspaceId string + metadata *UpdateWorkspaceProviderMetadataDTO } -func (r ApiStopWorkspaceRequest) Execute() (*http.Response, error) { - return r.ApiService.StopWorkspaceExecute(r) +// Provider metadata +func (r ApiUpdateWorkspaceProviderMetadataRequest) Metadata(metadata UpdateWorkspaceProviderMetadataDTO) ApiUpdateWorkspaceProviderMetadataRequest { + r.metadata = &metadata + return r +} + +func (r ApiUpdateWorkspaceProviderMetadataRequest) Execute() (*http.Response, error) { + return r.ApiService.UpdateWorkspaceProviderMetadataExecute(r) } /* -StopWorkspace Stop workspace +UpdateWorkspaceProviderMetadata Update workspace provider metadata -Stop workspace +Update workspace provider metadata @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). - @param workspaceId Workspace ID or Name - @return ApiStopWorkspaceRequest + @param workspaceId Workspace ID + @return ApiUpdateWorkspaceProviderMetadataRequest */ -func (a *WorkspaceAPIService) StopWorkspace(ctx context.Context, workspaceId string) ApiStopWorkspaceRequest { - return ApiStopWorkspaceRequest{ +func (a *WorkspaceAPIService) UpdateWorkspaceProviderMetadata(ctx context.Context, workspaceId string) ApiUpdateWorkspaceProviderMetadataRequest { + return ApiUpdateWorkspaceProviderMetadataRequest{ ApiService: a, ctx: ctx, workspaceId: workspaceId, @@ -992,24 +1225,27 @@ func (a *WorkspaceAPIService) StopWorkspace(ctx context.Context, workspaceId str } // Execute executes the request -func (a *WorkspaceAPIService) StopWorkspaceExecute(r ApiStopWorkspaceRequest) (*http.Response, error) { +func (a *WorkspaceAPIService) UpdateWorkspaceProviderMetadataExecute(r ApiUpdateWorkspaceProviderMetadataRequest) (*http.Response, error) { var ( localVarHTTPMethod = http.MethodPost localVarPostBody interface{} formFiles []formFile ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "WorkspaceAPIService.StopWorkspace") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "WorkspaceAPIService.UpdateWorkspaceProviderMetadata") if err != nil { return nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/workspace/{workspaceId}/stop" + localVarPath := localBasePath + "/workspace/{workspaceId}/provider-metadata" localVarPath = strings.Replace(localVarPath, "{"+"workspaceId"+"}", url.PathEscape(parameterValueToString(r.workspaceId, "workspaceId")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} localVarFormParams := url.Values{} + if r.metadata == nil { + return nil, reportError("metadata is required and must be specified") + } // to determine the Content-Type header localVarHTTPContentTypes := []string{} @@ -1028,6 +1264,8 @@ func (a *WorkspaceAPIService) StopWorkspaceExecute(r ApiStopWorkspaceRequest) (* if localVarHTTPHeaderAccept != "" { localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept } + // body params + localVarPostBody = r.metadata if r.ctx != nil { // API Key Authentication if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { diff --git a/pkg/apiclient/api_project_config.go b/pkg/apiclient/api_workspace_template.go similarity index 70% rename from pkg/apiclient/api_project_config.go rename to pkg/apiclient/api_workspace_template.go index a42a381a59..a1ad8eb23f 100644 --- a/pkg/apiclient/api_project_config.go +++ b/pkg/apiclient/api_workspace_template.go @@ -19,58 +19,58 @@ import ( "strings" ) -// ProjectConfigAPIService ProjectConfigAPI service -type ProjectConfigAPIService service - -type ApiDeleteProjectConfigRequest struct { - ctx context.Context - ApiService *ProjectConfigAPIService - configName string - force *bool +// WorkspaceTemplateAPIService WorkspaceTemplateAPI service +type WorkspaceTemplateAPIService service + +type ApiDeleteWorkspaceTemplateRequest struct { + ctx context.Context + ApiService *WorkspaceTemplateAPIService + templateName string + force *bool } // Force -func (r ApiDeleteProjectConfigRequest) Force(force bool) ApiDeleteProjectConfigRequest { +func (r ApiDeleteWorkspaceTemplateRequest) Force(force bool) ApiDeleteWorkspaceTemplateRequest { r.force = &force return r } -func (r ApiDeleteProjectConfigRequest) Execute() (*http.Response, error) { - return r.ApiService.DeleteProjectConfigExecute(r) +func (r ApiDeleteWorkspaceTemplateRequest) Execute() (*http.Response, error) { + return r.ApiService.DeleteWorkspaceTemplateExecute(r) } /* -DeleteProjectConfig Delete project config data +DeleteWorkspaceTemplate Delete workspace template data -Delete project config data +Delete workspace template data @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). - @param configName Config name - @return ApiDeleteProjectConfigRequest + @param templateName Template name + @return ApiDeleteWorkspaceTemplateRequest */ -func (a *ProjectConfigAPIService) DeleteProjectConfig(ctx context.Context, configName string) ApiDeleteProjectConfigRequest { - return ApiDeleteProjectConfigRequest{ - ApiService: a, - ctx: ctx, - configName: configName, +func (a *WorkspaceTemplateAPIService) DeleteWorkspaceTemplate(ctx context.Context, templateName string) ApiDeleteWorkspaceTemplateRequest { + return ApiDeleteWorkspaceTemplateRequest{ + ApiService: a, + ctx: ctx, + templateName: templateName, } } // Execute executes the request -func (a *ProjectConfigAPIService) DeleteProjectConfigExecute(r ApiDeleteProjectConfigRequest) (*http.Response, error) { +func (a *WorkspaceTemplateAPIService) DeleteWorkspaceTemplateExecute(r ApiDeleteWorkspaceTemplateRequest) (*http.Response, error) { var ( localVarHTTPMethod = http.MethodDelete localVarPostBody interface{} formFiles []formFile ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "ProjectConfigAPIService.DeleteProjectConfig") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "WorkspaceTemplateAPIService.DeleteWorkspaceTemplate") if err != nil { return nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/project-config/{configName}" - localVarPath = strings.Replace(localVarPath, "{"+"configName"+"}", url.PathEscape(parameterValueToString(r.configName, "configName")), -1) + localVarPath := localBasePath + "/workspace-template/{templateName}" + localVarPath = strings.Replace(localVarPath, "{"+"templateName"+"}", url.PathEscape(parameterValueToString(r.templateName, "templateName")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -138,51 +138,51 @@ func (a *ProjectConfigAPIService) DeleteProjectConfigExecute(r ApiDeleteProjectC return localVarHTTPResponse, nil } -type ApiGetDefaultProjectConfigRequest struct { - ctx context.Context - ApiService *ProjectConfigAPIService - gitUrl string +type ApiFindWorkspaceTemplateRequest struct { + ctx context.Context + ApiService *WorkspaceTemplateAPIService + templateName string } -func (r ApiGetDefaultProjectConfigRequest) Execute() (*ProjectConfig, *http.Response, error) { - return r.ApiService.GetDefaultProjectConfigExecute(r) +func (r ApiFindWorkspaceTemplateRequest) Execute() (*WorkspaceTemplate, *http.Response, error) { + return r.ApiService.FindWorkspaceTemplateExecute(r) } /* -GetDefaultProjectConfig Get project configs by git url +FindWorkspaceTemplate Find a workspace template -Get project configs by git url +Find a workspace template @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). - @param gitUrl Git URL - @return ApiGetDefaultProjectConfigRequest + @param templateName Template name + @return ApiFindWorkspaceTemplateRequest */ -func (a *ProjectConfigAPIService) GetDefaultProjectConfig(ctx context.Context, gitUrl string) ApiGetDefaultProjectConfigRequest { - return ApiGetDefaultProjectConfigRequest{ - ApiService: a, - ctx: ctx, - gitUrl: gitUrl, +func (a *WorkspaceTemplateAPIService) FindWorkspaceTemplate(ctx context.Context, templateName string) ApiFindWorkspaceTemplateRequest { + return ApiFindWorkspaceTemplateRequest{ + ApiService: a, + ctx: ctx, + templateName: templateName, } } // Execute executes the request // -// @return ProjectConfig -func (a *ProjectConfigAPIService) GetDefaultProjectConfigExecute(r ApiGetDefaultProjectConfigRequest) (*ProjectConfig, *http.Response, error) { +// @return WorkspaceTemplate +func (a *WorkspaceTemplateAPIService) FindWorkspaceTemplateExecute(r ApiFindWorkspaceTemplateRequest) (*WorkspaceTemplate, *http.Response, error) { var ( localVarHTTPMethod = http.MethodGet localVarPostBody interface{} formFiles []formFile - localVarReturnValue *ProjectConfig + localVarReturnValue *WorkspaceTemplate ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "ProjectConfigAPIService.GetDefaultProjectConfig") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "WorkspaceTemplateAPIService.FindWorkspaceTemplate") if err != nil { return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/project-config/default/{gitUrl}" - localVarPath = strings.Replace(localVarPath, "{"+"gitUrl"+"}", url.PathEscape(parameterValueToString(r.gitUrl, "gitUrl")), -1) + localVarPath := localBasePath + "/workspace-template/{templateName}" + localVarPath = strings.Replace(localVarPath, "{"+"templateName"+"}", url.PathEscape(parameterValueToString(r.templateName, "templateName")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -198,7 +198,7 @@ func (a *ProjectConfigAPIService) GetDefaultProjectConfigExecute(r ApiGetDefault } // to determine the Accept header - localVarHTTPHeaderAccepts := []string{"application/json"} + localVarHTTPHeaderAccepts := []string{"*/*"} // set Accept header localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) @@ -256,51 +256,51 @@ func (a *ProjectConfigAPIService) GetDefaultProjectConfigExecute(r ApiGetDefault return localVarReturnValue, localVarHTTPResponse, nil } -type ApiGetProjectConfigRequest struct { +type ApiGetDefaultWorkspaceTemplateRequest struct { ctx context.Context - ApiService *ProjectConfigAPIService - configName string + ApiService *WorkspaceTemplateAPIService + gitUrl string } -func (r ApiGetProjectConfigRequest) Execute() (*ProjectConfig, *http.Response, error) { - return r.ApiService.GetProjectConfigExecute(r) +func (r ApiGetDefaultWorkspaceTemplateRequest) Execute() (*WorkspaceTemplate, *http.Response, error) { + return r.ApiService.GetDefaultWorkspaceTemplateExecute(r) } /* -GetProjectConfig Get project config data +GetDefaultWorkspaceTemplate Get default workspace templates by git url -Get project config data +Get default workspace templates by git url @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). - @param configName Config name - @return ApiGetProjectConfigRequest + @param gitUrl Git URL + @return ApiGetDefaultWorkspaceTemplateRequest */ -func (a *ProjectConfigAPIService) GetProjectConfig(ctx context.Context, configName string) ApiGetProjectConfigRequest { - return ApiGetProjectConfigRequest{ +func (a *WorkspaceTemplateAPIService) GetDefaultWorkspaceTemplate(ctx context.Context, gitUrl string) ApiGetDefaultWorkspaceTemplateRequest { + return ApiGetDefaultWorkspaceTemplateRequest{ ApiService: a, ctx: ctx, - configName: configName, + gitUrl: gitUrl, } } // Execute executes the request // -// @return ProjectConfig -func (a *ProjectConfigAPIService) GetProjectConfigExecute(r ApiGetProjectConfigRequest) (*ProjectConfig, *http.Response, error) { +// @return WorkspaceTemplate +func (a *WorkspaceTemplateAPIService) GetDefaultWorkspaceTemplateExecute(r ApiGetDefaultWorkspaceTemplateRequest) (*WorkspaceTemplate, *http.Response, error) { var ( localVarHTTPMethod = http.MethodGet localVarPostBody interface{} formFiles []formFile - localVarReturnValue *ProjectConfig + localVarReturnValue *WorkspaceTemplate ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "ProjectConfigAPIService.GetProjectConfig") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "WorkspaceTemplateAPIService.GetDefaultWorkspaceTemplate") if err != nil { return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/project-config/{configName}" - localVarPath = strings.Replace(localVarPath, "{"+"configName"+"}", url.PathEscape(parameterValueToString(r.configName, "configName")), -1) + localVarPath := localBasePath + "/workspace-template/default/{gitUrl}" + localVarPath = strings.Replace(localVarPath, "{"+"gitUrl"+"}", url.PathEscape(parameterValueToString(r.gitUrl, "gitUrl")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -316,7 +316,7 @@ func (a *ProjectConfigAPIService) GetProjectConfigExecute(r ApiGetProjectConfigR } // to determine the Accept header - localVarHTTPHeaderAccepts := []string{"*/*"} + localVarHTTPHeaderAccepts := []string{"application/json"} // set Accept header localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) @@ -374,25 +374,25 @@ func (a *ProjectConfigAPIService) GetProjectConfigExecute(r ApiGetProjectConfigR return localVarReturnValue, localVarHTTPResponse, nil } -type ApiListProjectConfigsRequest struct { +type ApiListWorkspaceTemplatesRequest struct { ctx context.Context - ApiService *ProjectConfigAPIService + ApiService *WorkspaceTemplateAPIService } -func (r ApiListProjectConfigsRequest) Execute() ([]ProjectConfig, *http.Response, error) { - return r.ApiService.ListProjectConfigsExecute(r) +func (r ApiListWorkspaceTemplatesRequest) Execute() ([]WorkspaceTemplate, *http.Response, error) { + return r.ApiService.ListWorkspaceTemplatesExecute(r) } /* -ListProjectConfigs List project configs +ListWorkspaceTemplates List workspace templates -List project configs +List workspace templates @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). - @return ApiListProjectConfigsRequest + @return ApiListWorkspaceTemplatesRequest */ -func (a *ProjectConfigAPIService) ListProjectConfigs(ctx context.Context) ApiListProjectConfigsRequest { - return ApiListProjectConfigsRequest{ +func (a *WorkspaceTemplateAPIService) ListWorkspaceTemplates(ctx context.Context) ApiListWorkspaceTemplatesRequest { + return ApiListWorkspaceTemplatesRequest{ ApiService: a, ctx: ctx, } @@ -400,21 +400,21 @@ func (a *ProjectConfigAPIService) ListProjectConfigs(ctx context.Context) ApiLis // Execute executes the request // -// @return []ProjectConfig -func (a *ProjectConfigAPIService) ListProjectConfigsExecute(r ApiListProjectConfigsRequest) ([]ProjectConfig, *http.Response, error) { +// @return []WorkspaceTemplate +func (a *WorkspaceTemplateAPIService) ListWorkspaceTemplatesExecute(r ApiListWorkspaceTemplatesRequest) ([]WorkspaceTemplate, *http.Response, error) { var ( localVarHTTPMethod = http.MethodGet localVarPostBody interface{} formFiles []formFile - localVarReturnValue []ProjectConfig + localVarReturnValue []WorkspaceTemplate ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "ProjectConfigAPIService.ListProjectConfigs") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "WorkspaceTemplateAPIService.ListWorkspaceTemplates") if err != nil { return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/project-config" + localVarPath := localBasePath + "/workspace-template" localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -488,55 +488,61 @@ func (a *ProjectConfigAPIService) ListProjectConfigsExecute(r ApiListProjectConf return localVarReturnValue, localVarHTTPResponse, nil } -type ApiSetDefaultProjectConfigRequest struct { - ctx context.Context - ApiService *ProjectConfigAPIService - configName string +type ApiSaveWorkspaceTemplateRequest struct { + ctx context.Context + ApiService *WorkspaceTemplateAPIService + workspaceTemplate *CreateWorkspaceTemplateDTO } -func (r ApiSetDefaultProjectConfigRequest) Execute() (*http.Response, error) { - return r.ApiService.SetDefaultProjectConfigExecute(r) +// Workspace template +func (r ApiSaveWorkspaceTemplateRequest) WorkspaceTemplate(workspaceTemplate CreateWorkspaceTemplateDTO) ApiSaveWorkspaceTemplateRequest { + r.workspaceTemplate = &workspaceTemplate + return r +} + +func (r ApiSaveWorkspaceTemplateRequest) Execute() (*http.Response, error) { + return r.ApiService.SaveWorkspaceTemplateExecute(r) } /* -SetDefaultProjectConfig Set project config to default +SaveWorkspaceTemplate Set workspace template data -Set project config to default +Set workspace template data @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). - @param configName Config name - @return ApiSetDefaultProjectConfigRequest + @return ApiSaveWorkspaceTemplateRequest */ -func (a *ProjectConfigAPIService) SetDefaultProjectConfig(ctx context.Context, configName string) ApiSetDefaultProjectConfigRequest { - return ApiSetDefaultProjectConfigRequest{ +func (a *WorkspaceTemplateAPIService) SaveWorkspaceTemplate(ctx context.Context) ApiSaveWorkspaceTemplateRequest { + return ApiSaveWorkspaceTemplateRequest{ ApiService: a, ctx: ctx, - configName: configName, } } // Execute executes the request -func (a *ProjectConfigAPIService) SetDefaultProjectConfigExecute(r ApiSetDefaultProjectConfigRequest) (*http.Response, error) { +func (a *WorkspaceTemplateAPIService) SaveWorkspaceTemplateExecute(r ApiSaveWorkspaceTemplateRequest) (*http.Response, error) { var ( - localVarHTTPMethod = http.MethodPatch + localVarHTTPMethod = http.MethodPut localVarPostBody interface{} formFiles []formFile ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "ProjectConfigAPIService.SetDefaultProjectConfig") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "WorkspaceTemplateAPIService.SaveWorkspaceTemplate") if err != nil { return nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/project-config/{configName}/set-default" - localVarPath = strings.Replace(localVarPath, "{"+"configName"+"}", url.PathEscape(parameterValueToString(r.configName, "configName")), -1) + localVarPath := localBasePath + "/workspace-template" localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} localVarFormParams := url.Values{} + if r.workspaceTemplate == nil { + return nil, reportError("workspaceTemplate is required and must be specified") + } // to determine the Content-Type header - localVarHTTPContentTypes := []string{} + localVarHTTPContentTypes := []string{"application/json"} // set Content-Type header localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes) @@ -552,6 +558,8 @@ func (a *ProjectConfigAPIService) SetDefaultProjectConfigExecute(r ApiSetDefault if localVarHTTPHeaderAccept != "" { localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept } + // body params + localVarPostBody = r.workspaceTemplate if r.ctx != nil { // API Key Authentication if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { @@ -594,61 +602,55 @@ func (a *ProjectConfigAPIService) SetDefaultProjectConfigExecute(r ApiSetDefault return localVarHTTPResponse, nil } -type ApiSetProjectConfigRequest struct { - ctx context.Context - ApiService *ProjectConfigAPIService - projectConfig *CreateProjectConfigDTO -} - -// Project config -func (r ApiSetProjectConfigRequest) ProjectConfig(projectConfig CreateProjectConfigDTO) ApiSetProjectConfigRequest { - r.projectConfig = &projectConfig - return r +type ApiSetDefaultWorkspaceTemplateRequest struct { + ctx context.Context + ApiService *WorkspaceTemplateAPIService + templateName string } -func (r ApiSetProjectConfigRequest) Execute() (*http.Response, error) { - return r.ApiService.SetProjectConfigExecute(r) +func (r ApiSetDefaultWorkspaceTemplateRequest) Execute() (*http.Response, error) { + return r.ApiService.SetDefaultWorkspaceTemplateExecute(r) } /* -SetProjectConfig Set project config data +SetDefaultWorkspaceTemplate Set workspace template to default -Set project config data +Set workspace template to default @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). - @return ApiSetProjectConfigRequest + @param templateName Template name + @return ApiSetDefaultWorkspaceTemplateRequest */ -func (a *ProjectConfigAPIService) SetProjectConfig(ctx context.Context) ApiSetProjectConfigRequest { - return ApiSetProjectConfigRequest{ - ApiService: a, - ctx: ctx, +func (a *WorkspaceTemplateAPIService) SetDefaultWorkspaceTemplate(ctx context.Context, templateName string) ApiSetDefaultWorkspaceTemplateRequest { + return ApiSetDefaultWorkspaceTemplateRequest{ + ApiService: a, + ctx: ctx, + templateName: templateName, } } // Execute executes the request -func (a *ProjectConfigAPIService) SetProjectConfigExecute(r ApiSetProjectConfigRequest) (*http.Response, error) { +func (a *WorkspaceTemplateAPIService) SetDefaultWorkspaceTemplateExecute(r ApiSetDefaultWorkspaceTemplateRequest) (*http.Response, error) { var ( - localVarHTTPMethod = http.MethodPut + localVarHTTPMethod = http.MethodPatch localVarPostBody interface{} formFiles []formFile ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "ProjectConfigAPIService.SetProjectConfig") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "WorkspaceTemplateAPIService.SetDefaultWorkspaceTemplate") if err != nil { return nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/project-config" + localVarPath := localBasePath + "/workspace-template/{templateName}/set-default" + localVarPath = strings.Replace(localVarPath, "{"+"templateName"+"}", url.PathEscape(parameterValueToString(r.templateName, "templateName")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} localVarFormParams := url.Values{} - if r.projectConfig == nil { - return nil, reportError("projectConfig is required and must be specified") - } // to determine the Content-Type header - localVarHTTPContentTypes := []string{"application/json"} + localVarHTTPContentTypes := []string{} // set Content-Type header localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes) @@ -664,8 +666,6 @@ func (a *ProjectConfigAPIService) SetProjectConfigExecute(r ApiSetProjectConfigR if localVarHTTPHeaderAccept != "" { localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept } - // body params - localVarPostBody = r.projectConfig if r.ctx != nil { // API Key Authentication if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { diff --git a/pkg/apiclient/api_workspace_toolbox.go b/pkg/apiclient/api_workspace_toolbox.go index fa9a17ba8c..30535b2a27 100644 --- a/pkg/apiclient/api_workspace_toolbox.go +++ b/pkg/apiclient/api_workspace_toolbox.go @@ -27,7 +27,6 @@ type ApiCreateSessionRequest struct { ctx context.Context ApiService *WorkspaceToolboxAPIService workspaceId string - projectId string params *CreateSessionRequest } @@ -48,15 +47,13 @@ Create exec session inside workspace project @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @param workspaceId Workspace ID or Name - @param projectId Project ID @return ApiCreateSessionRequest */ -func (a *WorkspaceToolboxAPIService) CreateSession(ctx context.Context, workspaceId string, projectId string) ApiCreateSessionRequest { +func (a *WorkspaceToolboxAPIService) CreateSession(ctx context.Context, workspaceId string) ApiCreateSessionRequest { return ApiCreateSessionRequest{ ApiService: a, ctx: ctx, workspaceId: workspaceId, - projectId: projectId, } } @@ -73,9 +70,8 @@ func (a *WorkspaceToolboxAPIService) CreateSessionExecute(r ApiCreateSessionRequ return nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/workspace/{workspaceId}/{projectId}/toolbox/process/session" + localVarPath := localBasePath + "/workspace/{workspaceId}/toolbox/process/session" localVarPath = strings.Replace(localVarPath, "{"+"workspaceId"+"}", url.PathEscape(parameterValueToString(r.workspaceId, "workspaceId")), -1) - localVarPath = strings.Replace(localVarPath, "{"+"projectId"+"}", url.PathEscape(parameterValueToString(r.projectId, "projectId")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -149,7 +145,6 @@ type ApiDeleteSessionRequest struct { ctx context.Context ApiService *WorkspaceToolboxAPIService workspaceId string - projectId string sessionId string } @@ -164,16 +159,14 @@ Delete a session inside workspace project @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @param workspaceId Workspace ID or Name - @param projectId Project ID @param sessionId Session ID @return ApiDeleteSessionRequest */ -func (a *WorkspaceToolboxAPIService) DeleteSession(ctx context.Context, workspaceId string, projectId string, sessionId string) ApiDeleteSessionRequest { +func (a *WorkspaceToolboxAPIService) DeleteSession(ctx context.Context, workspaceId string, sessionId string) ApiDeleteSessionRequest { return ApiDeleteSessionRequest{ ApiService: a, ctx: ctx, workspaceId: workspaceId, - projectId: projectId, sessionId: sessionId, } } @@ -191,9 +184,8 @@ func (a *WorkspaceToolboxAPIService) DeleteSessionExecute(r ApiDeleteSessionRequ return nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/workspace/{workspaceId}/{projectId}/toolbox/process/session/{sessionId}" + localVarPath := localBasePath + "/workspace/{workspaceId}/toolbox/process/session/{sessionId}" localVarPath = strings.Replace(localVarPath, "{"+"workspaceId"+"}", url.PathEscape(parameterValueToString(r.workspaceId, "workspaceId")), -1) - localVarPath = strings.Replace(localVarPath, "{"+"projectId"+"}", url.PathEscape(parameterValueToString(r.projectId, "projectId")), -1) localVarPath = strings.Replace(localVarPath, "{"+"sessionId"+"}", url.PathEscape(parameterValueToString(r.sessionId, "sessionId")), -1) localVarHeaderParams := make(map[string]string) @@ -263,7 +255,6 @@ type ApiFsCreateFolderRequest struct { ctx context.Context ApiService *WorkspaceToolboxAPIService workspaceId string - projectId string path *string mode *string } @@ -287,19 +278,17 @@ func (r ApiFsCreateFolderRequest) Execute() (*http.Response, error) { /* FsCreateFolder Create folder -Create folder inside workspace project +Create folder inside a workspace @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @param workspaceId Workspace ID or Name - @param projectId Project ID @return ApiFsCreateFolderRequest */ -func (a *WorkspaceToolboxAPIService) FsCreateFolder(ctx context.Context, workspaceId string, projectId string) ApiFsCreateFolderRequest { +func (a *WorkspaceToolboxAPIService) FsCreateFolder(ctx context.Context, workspaceId string) ApiFsCreateFolderRequest { return ApiFsCreateFolderRequest{ ApiService: a, ctx: ctx, workspaceId: workspaceId, - projectId: projectId, } } @@ -316,9 +305,8 @@ func (a *WorkspaceToolboxAPIService) FsCreateFolderExecute(r ApiFsCreateFolderRe return nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/workspace/{workspaceId}/{projectId}/toolbox/files/folder" + localVarPath := localBasePath + "/workspace/{workspaceId}/toolbox/files/folder" localVarPath = strings.Replace(localVarPath, "{"+"workspaceId"+"}", url.PathEscape(parameterValueToString(r.workspaceId, "workspaceId")), -1) - localVarPath = strings.Replace(localVarPath, "{"+"projectId"+"}", url.PathEscape(parameterValueToString(r.projectId, "projectId")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -395,7 +383,6 @@ type ApiFsDeleteFileRequest struct { ctx context.Context ApiService *WorkspaceToolboxAPIService workspaceId string - projectId string path *string } @@ -412,19 +399,17 @@ func (r ApiFsDeleteFileRequest) Execute() (*http.Response, error) { /* FsDeleteFile Delete file -Delete file inside workspace project +Delete file inside a workspace @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @param workspaceId Workspace ID or Name - @param projectId Project ID @return ApiFsDeleteFileRequest */ -func (a *WorkspaceToolboxAPIService) FsDeleteFile(ctx context.Context, workspaceId string, projectId string) ApiFsDeleteFileRequest { +func (a *WorkspaceToolboxAPIService) FsDeleteFile(ctx context.Context, workspaceId string) ApiFsDeleteFileRequest { return ApiFsDeleteFileRequest{ ApiService: a, ctx: ctx, workspaceId: workspaceId, - projectId: projectId, } } @@ -441,9 +426,8 @@ func (a *WorkspaceToolboxAPIService) FsDeleteFileExecute(r ApiFsDeleteFileReques return nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/workspace/{workspaceId}/{projectId}/toolbox/files" + localVarPath := localBasePath + "/workspace/{workspaceId}/toolbox/files" localVarPath = strings.Replace(localVarPath, "{"+"workspaceId"+"}", url.PathEscape(parameterValueToString(r.workspaceId, "workspaceId")), -1) - localVarPath = strings.Replace(localVarPath, "{"+"projectId"+"}", url.PathEscape(parameterValueToString(r.projectId, "projectId")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -516,7 +500,6 @@ type ApiFsDownloadFileRequest struct { ctx context.Context ApiService *WorkspaceToolboxAPIService workspaceId string - projectId string path *string } @@ -533,19 +516,17 @@ func (r ApiFsDownloadFileRequest) Execute() (*os.File, *http.Response, error) { /* FsDownloadFile Download file -Download file from workspace project +Download file from a workspace @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @param workspaceId Workspace ID or Name - @param projectId Project ID @return ApiFsDownloadFileRequest */ -func (a *WorkspaceToolboxAPIService) FsDownloadFile(ctx context.Context, workspaceId string, projectId string) ApiFsDownloadFileRequest { +func (a *WorkspaceToolboxAPIService) FsDownloadFile(ctx context.Context, workspaceId string) ApiFsDownloadFileRequest { return ApiFsDownloadFileRequest{ ApiService: a, ctx: ctx, workspaceId: workspaceId, - projectId: projectId, } } @@ -565,9 +546,8 @@ func (a *WorkspaceToolboxAPIService) FsDownloadFileExecute(r ApiFsDownloadFileRe return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/workspace/{workspaceId}/{projectId}/toolbox/files/download" + localVarPath := localBasePath + "/workspace/{workspaceId}/toolbox/files/download" localVarPath = strings.Replace(localVarPath, "{"+"workspaceId"+"}", url.PathEscape(parameterValueToString(r.workspaceId, "workspaceId")), -1) - localVarPath = strings.Replace(localVarPath, "{"+"projectId"+"}", url.PathEscape(parameterValueToString(r.projectId, "projectId")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -649,7 +629,6 @@ type ApiFsFindInFilesRequest struct { ctx context.Context ApiService *WorkspaceToolboxAPIService workspaceId string - projectId string path *string pattern *string } @@ -673,19 +652,17 @@ func (r ApiFsFindInFilesRequest) Execute() ([]Match, *http.Response, error) { /* FsFindInFiles Search for text/pattern in files -Search for text/pattern inside workspace project files +Search for text/pattern inside a workspace files @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @param workspaceId Workspace ID or Name - @param projectId Project ID @return ApiFsFindInFilesRequest */ -func (a *WorkspaceToolboxAPIService) FsFindInFiles(ctx context.Context, workspaceId string, projectId string) ApiFsFindInFilesRequest { +func (a *WorkspaceToolboxAPIService) FsFindInFiles(ctx context.Context, workspaceId string) ApiFsFindInFilesRequest { return ApiFsFindInFilesRequest{ ApiService: a, ctx: ctx, workspaceId: workspaceId, - projectId: projectId, } } @@ -705,9 +682,8 @@ func (a *WorkspaceToolboxAPIService) FsFindInFilesExecute(r ApiFsFindInFilesRequ return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/workspace/{workspaceId}/{projectId}/toolbox/files/find" + localVarPath := localBasePath + "/workspace/{workspaceId}/toolbox/files/find" localVarPath = strings.Replace(localVarPath, "{"+"workspaceId"+"}", url.PathEscape(parameterValueToString(r.workspaceId, "workspaceId")), -1) - localVarPath = strings.Replace(localVarPath, "{"+"projectId"+"}", url.PathEscape(parameterValueToString(r.projectId, "projectId")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -793,7 +769,6 @@ type ApiFsGetFileDetailsRequest struct { ctx context.Context ApiService *WorkspaceToolboxAPIService workspaceId string - projectId string path *string } @@ -810,19 +785,17 @@ func (r ApiFsGetFileDetailsRequest) Execute() (*FileInfo, *http.Response, error) /* FsGetFileDetails Get file info -Get file info inside workspace project +Get file info inside a workspace @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @param workspaceId Workspace ID or Name - @param projectId Project ID @return ApiFsGetFileDetailsRequest */ -func (a *WorkspaceToolboxAPIService) FsGetFileDetails(ctx context.Context, workspaceId string, projectId string) ApiFsGetFileDetailsRequest { +func (a *WorkspaceToolboxAPIService) FsGetFileDetails(ctx context.Context, workspaceId string) ApiFsGetFileDetailsRequest { return ApiFsGetFileDetailsRequest{ ApiService: a, ctx: ctx, workspaceId: workspaceId, - projectId: projectId, } } @@ -842,9 +815,8 @@ func (a *WorkspaceToolboxAPIService) FsGetFileDetailsExecute(r ApiFsGetFileDetai return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/workspace/{workspaceId}/{projectId}/toolbox/files/info" + localVarPath := localBasePath + "/workspace/{workspaceId}/toolbox/files/info" localVarPath = strings.Replace(localVarPath, "{"+"workspaceId"+"}", url.PathEscape(parameterValueToString(r.workspaceId, "workspaceId")), -1) - localVarPath = strings.Replace(localVarPath, "{"+"projectId"+"}", url.PathEscape(parameterValueToString(r.projectId, "projectId")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -926,7 +898,6 @@ type ApiFsListFilesRequest struct { ctx context.Context ApiService *WorkspaceToolboxAPIService workspaceId string - projectId string path *string } @@ -943,19 +914,17 @@ func (r ApiFsListFilesRequest) Execute() ([]FileInfo, *http.Response, error) { /* FsListFiles List files -List files inside workspace project +List files inside a workspace @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @param workspaceId Workspace ID or Name - @param projectId Project ID @return ApiFsListFilesRequest */ -func (a *WorkspaceToolboxAPIService) FsListFiles(ctx context.Context, workspaceId string, projectId string) ApiFsListFilesRequest { +func (a *WorkspaceToolboxAPIService) FsListFiles(ctx context.Context, workspaceId string) ApiFsListFilesRequest { return ApiFsListFilesRequest{ ApiService: a, ctx: ctx, workspaceId: workspaceId, - projectId: projectId, } } @@ -975,9 +944,8 @@ func (a *WorkspaceToolboxAPIService) FsListFilesExecute(r ApiFsListFilesRequest) return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/workspace/{workspaceId}/{projectId}/toolbox/files" + localVarPath := localBasePath + "/workspace/{workspaceId}/toolbox/files" localVarPath = strings.Replace(localVarPath, "{"+"workspaceId"+"}", url.PathEscape(parameterValueToString(r.workspaceId, "workspaceId")), -1) - localVarPath = strings.Replace(localVarPath, "{"+"projectId"+"}", url.PathEscape(parameterValueToString(r.projectId, "projectId")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -1058,7 +1026,6 @@ type ApiFsMoveFileRequest struct { ctx context.Context ApiService *WorkspaceToolboxAPIService workspaceId string - projectId string source *string destination *string } @@ -1082,19 +1049,17 @@ func (r ApiFsMoveFileRequest) Execute() (*http.Response, error) { /* FsMoveFile Create folder -Create folder inside workspace project +Create folder inside a workspace @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @param workspaceId Workspace ID or Name - @param projectId Project ID @return ApiFsMoveFileRequest */ -func (a *WorkspaceToolboxAPIService) FsMoveFile(ctx context.Context, workspaceId string, projectId string) ApiFsMoveFileRequest { +func (a *WorkspaceToolboxAPIService) FsMoveFile(ctx context.Context, workspaceId string) ApiFsMoveFileRequest { return ApiFsMoveFileRequest{ ApiService: a, ctx: ctx, workspaceId: workspaceId, - projectId: projectId, } } @@ -1111,9 +1076,8 @@ func (a *WorkspaceToolboxAPIService) FsMoveFileExecute(r ApiFsMoveFileRequest) ( return nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/workspace/{workspaceId}/{projectId}/toolbox/files/move" + localVarPath := localBasePath + "/workspace/{workspaceId}/toolbox/files/move" localVarPath = strings.Replace(localVarPath, "{"+"workspaceId"+"}", url.PathEscape(parameterValueToString(r.workspaceId, "workspaceId")), -1) - localVarPath = strings.Replace(localVarPath, "{"+"projectId"+"}", url.PathEscape(parameterValueToString(r.projectId, "projectId")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -1190,7 +1154,6 @@ type ApiFsReplaceInFilesRequest struct { ctx context.Context ApiService *WorkspaceToolboxAPIService workspaceId string - projectId string replace *ReplaceRequest } @@ -1207,19 +1170,17 @@ func (r ApiFsReplaceInFilesRequest) Execute() ([]ReplaceResult, *http.Response, /* FsReplaceInFiles Repleace text/pattern in files -Repleace text/pattern in mutilple files inside workspace project +Repleace text/pattern in mutilple files inside a workspace @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @param workspaceId Workspace ID or Name - @param projectId Project ID @return ApiFsReplaceInFilesRequest */ -func (a *WorkspaceToolboxAPIService) FsReplaceInFiles(ctx context.Context, workspaceId string, projectId string) ApiFsReplaceInFilesRequest { +func (a *WorkspaceToolboxAPIService) FsReplaceInFiles(ctx context.Context, workspaceId string) ApiFsReplaceInFilesRequest { return ApiFsReplaceInFilesRequest{ ApiService: a, ctx: ctx, workspaceId: workspaceId, - projectId: projectId, } } @@ -1239,9 +1200,8 @@ func (a *WorkspaceToolboxAPIService) FsReplaceInFilesExecute(r ApiFsReplaceInFil return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/workspace/{workspaceId}/{projectId}/toolbox/files/replace" + localVarPath := localBasePath + "/workspace/{workspaceId}/toolbox/files/replace" localVarPath = strings.Replace(localVarPath, "{"+"workspaceId"+"}", url.PathEscape(parameterValueToString(r.workspaceId, "workspaceId")), -1) - localVarPath = strings.Replace(localVarPath, "{"+"projectId"+"}", url.PathEscape(parameterValueToString(r.projectId, "projectId")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -1324,7 +1284,6 @@ type ApiFsSearchFilesRequest struct { ctx context.Context ApiService *WorkspaceToolboxAPIService workspaceId string - projectId string path *string pattern *string } @@ -1348,19 +1307,17 @@ func (r ApiFsSearchFilesRequest) Execute() (*SearchFilesResponse, *http.Response /* FsSearchFiles Search for files -Search for files inside workspace project +Search for files inside a workspace @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @param workspaceId Workspace ID or Name - @param projectId Project ID @return ApiFsSearchFilesRequest */ -func (a *WorkspaceToolboxAPIService) FsSearchFiles(ctx context.Context, workspaceId string, projectId string) ApiFsSearchFilesRequest { +func (a *WorkspaceToolboxAPIService) FsSearchFiles(ctx context.Context, workspaceId string) ApiFsSearchFilesRequest { return ApiFsSearchFilesRequest{ ApiService: a, ctx: ctx, workspaceId: workspaceId, - projectId: projectId, } } @@ -1380,9 +1337,8 @@ func (a *WorkspaceToolboxAPIService) FsSearchFilesExecute(r ApiFsSearchFilesRequ return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/workspace/{workspaceId}/{projectId}/toolbox/files/search" + localVarPath := localBasePath + "/workspace/{workspaceId}/toolbox/files/search" localVarPath = strings.Replace(localVarPath, "{"+"workspaceId"+"}", url.PathEscape(parameterValueToString(r.workspaceId, "workspaceId")), -1) - localVarPath = strings.Replace(localVarPath, "{"+"projectId"+"}", url.PathEscape(parameterValueToString(r.projectId, "projectId")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -1468,7 +1424,6 @@ type ApiFsSetFilePermissionsRequest struct { ctx context.Context ApiService *WorkspaceToolboxAPIService workspaceId string - projectId string path *string owner *string group *string @@ -1506,19 +1461,17 @@ func (r ApiFsSetFilePermissionsRequest) Execute() (*http.Response, error) { /* FsSetFilePermissions Set file owner/group/permissions -Set file owner/group/permissions inside workspace project +Set file owner/group/permissions inside a workspace @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @param workspaceId Workspace ID or Name - @param projectId Project ID @return ApiFsSetFilePermissionsRequest */ -func (a *WorkspaceToolboxAPIService) FsSetFilePermissions(ctx context.Context, workspaceId string, projectId string) ApiFsSetFilePermissionsRequest { +func (a *WorkspaceToolboxAPIService) FsSetFilePermissions(ctx context.Context, workspaceId string) ApiFsSetFilePermissionsRequest { return ApiFsSetFilePermissionsRequest{ ApiService: a, ctx: ctx, workspaceId: workspaceId, - projectId: projectId, } } @@ -1535,9 +1488,8 @@ func (a *WorkspaceToolboxAPIService) FsSetFilePermissionsExecute(r ApiFsSetFileP return nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/workspace/{workspaceId}/{projectId}/toolbox/files/permissions" + localVarPath := localBasePath + "/workspace/{workspaceId}/toolbox/files/permissions" localVarPath = strings.Replace(localVarPath, "{"+"workspaceId"+"}", url.PathEscape(parameterValueToString(r.workspaceId, "workspaceId")), -1) - localVarPath = strings.Replace(localVarPath, "{"+"projectId"+"}", url.PathEscape(parameterValueToString(r.projectId, "projectId")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -1619,7 +1571,6 @@ type ApiFsUploadFileRequest struct { ctx context.Context ApiService *WorkspaceToolboxAPIService workspaceId string - projectId string path *string file *os.File } @@ -1643,19 +1594,17 @@ func (r ApiFsUploadFileRequest) Execute() (*http.Response, error) { /* FsUploadFile Upload file -Upload file inside workspace project +Upload file inside a workspace @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @param workspaceId Workspace ID or Name - @param projectId Project ID @return ApiFsUploadFileRequest */ -func (a *WorkspaceToolboxAPIService) FsUploadFile(ctx context.Context, workspaceId string, projectId string) ApiFsUploadFileRequest { +func (a *WorkspaceToolboxAPIService) FsUploadFile(ctx context.Context, workspaceId string) ApiFsUploadFileRequest { return ApiFsUploadFileRequest{ ApiService: a, ctx: ctx, workspaceId: workspaceId, - projectId: projectId, } } @@ -1672,9 +1621,8 @@ func (a *WorkspaceToolboxAPIService) FsUploadFileExecute(r ApiFsUploadFileReques return nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/workspace/{workspaceId}/{projectId}/toolbox/files/upload" + localVarPath := localBasePath + "/workspace/{workspaceId}/toolbox/files/upload" localVarPath = strings.Replace(localVarPath, "{"+"workspaceId"+"}", url.PathEscape(parameterValueToString(r.workspaceId, "workspaceId")), -1) - localVarPath = strings.Replace(localVarPath, "{"+"projectId"+"}", url.PathEscape(parameterValueToString(r.projectId, "projectId")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -1761,55 +1709,60 @@ func (a *WorkspaceToolboxAPIService) FsUploadFileExecute(r ApiFsUploadFileReques return localVarHTTPResponse, nil } -type ApiGetProjectDirRequest struct { +type ApiGetSessionCommandLogsRequest struct { ctx context.Context ApiService *WorkspaceToolboxAPIService workspaceId string - projectId string + sessionId string + commandId string } -func (r ApiGetProjectDirRequest) Execute() (*ProjectDirResponse, *http.Response, error) { - return r.ApiService.GetProjectDirExecute(r) +func (r ApiGetSessionCommandLogsRequest) Execute() (string, *http.Response, error) { + return r.ApiService.GetSessionCommandLogsExecute(r) } /* -GetProjectDir Get project dir +GetSessionCommandLogs Get session command logs -Get project directory +Get logs of a command inside a session inside workspace project +Connect with websocket to get a stream of the logs @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @param workspaceId Workspace ID or Name - @param projectId Project ID - @return ApiGetProjectDirRequest + @param sessionId Session ID + @param commandId Command ID + @return ApiGetSessionCommandLogsRequest */ -func (a *WorkspaceToolboxAPIService) GetProjectDir(ctx context.Context, workspaceId string, projectId string) ApiGetProjectDirRequest { - return ApiGetProjectDirRequest{ +func (a *WorkspaceToolboxAPIService) GetSessionCommandLogs(ctx context.Context, workspaceId string, sessionId string, commandId string) ApiGetSessionCommandLogsRequest { + return ApiGetSessionCommandLogsRequest{ ApiService: a, ctx: ctx, workspaceId: workspaceId, - projectId: projectId, + sessionId: sessionId, + commandId: commandId, } } // Execute executes the request // -// @return ProjectDirResponse -func (a *WorkspaceToolboxAPIService) GetProjectDirExecute(r ApiGetProjectDirRequest) (*ProjectDirResponse, *http.Response, error) { +// @return string +func (a *WorkspaceToolboxAPIService) GetSessionCommandLogsExecute(r ApiGetSessionCommandLogsRequest) (string, *http.Response, error) { var ( localVarHTTPMethod = http.MethodGet localVarPostBody interface{} formFiles []formFile - localVarReturnValue *ProjectDirResponse + localVarReturnValue string ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "WorkspaceToolboxAPIService.GetProjectDir") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "WorkspaceToolboxAPIService.GetSessionCommandLogs") if err != nil { return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/workspace/{workspaceId}/{projectId}/toolbox/project-dir" + localVarPath := localBasePath + "/workspace/{workspaceId}/toolbox/process/session/{sessionId}/command/{commandId}/logs" localVarPath = strings.Replace(localVarPath, "{"+"workspaceId"+"}", url.PathEscape(parameterValueToString(r.workspaceId, "workspaceId")), -1) - localVarPath = strings.Replace(localVarPath, "{"+"projectId"+"}", url.PathEscape(parameterValueToString(r.projectId, "projectId")), -1) + localVarPath = strings.Replace(localVarPath, "{"+"sessionId"+"}", url.PathEscape(parameterValueToString(r.sessionId, "sessionId")), -1) + localVarPath = strings.Replace(localVarPath, "{"+"commandId"+"}", url.PathEscape(parameterValueToString(r.commandId, "commandId")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -1825,7 +1778,7 @@ func (a *WorkspaceToolboxAPIService) GetProjectDirExecute(r ApiGetProjectDirRequ } // to determine the Accept header - localVarHTTPHeaderAccepts := []string{"application/json"} + localVarHTTPHeaderAccepts := []string{"*/*"} // set Accept header localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) @@ -1883,64 +1836,51 @@ func (a *WorkspaceToolboxAPIService) GetProjectDirExecute(r ApiGetProjectDirRequ return localVarReturnValue, localVarHTTPResponse, nil } -type ApiGetSessionCommandLogsRequest struct { +type ApiGetWorkspaceDirRequest struct { ctx context.Context ApiService *WorkspaceToolboxAPIService workspaceId string - projectId string - sessionId string - commandId string } -func (r ApiGetSessionCommandLogsRequest) Execute() (string, *http.Response, error) { - return r.ApiService.GetSessionCommandLogsExecute(r) +func (r ApiGetWorkspaceDirRequest) Execute() (*WorkspaceDirResponse, *http.Response, error) { + return r.ApiService.GetWorkspaceDirExecute(r) } /* -GetSessionCommandLogs Get session command logs +GetWorkspaceDir Get workspace dir -Get logs of a command inside a session inside workspace project -Connect with websocket to get a stream of the logs +Get workspace directory @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @param workspaceId Workspace ID or Name - @param projectId Project ID - @param sessionId Session ID - @param commandId Command ID - @return ApiGetSessionCommandLogsRequest + @return ApiGetWorkspaceDirRequest */ -func (a *WorkspaceToolboxAPIService) GetSessionCommandLogs(ctx context.Context, workspaceId string, projectId string, sessionId string, commandId string) ApiGetSessionCommandLogsRequest { - return ApiGetSessionCommandLogsRequest{ +func (a *WorkspaceToolboxAPIService) GetWorkspaceDir(ctx context.Context, workspaceId string) ApiGetWorkspaceDirRequest { + return ApiGetWorkspaceDirRequest{ ApiService: a, ctx: ctx, workspaceId: workspaceId, - projectId: projectId, - sessionId: sessionId, - commandId: commandId, } } // Execute executes the request // -// @return string -func (a *WorkspaceToolboxAPIService) GetSessionCommandLogsExecute(r ApiGetSessionCommandLogsRequest) (string, *http.Response, error) { +// @return WorkspaceDirResponse +func (a *WorkspaceToolboxAPIService) GetWorkspaceDirExecute(r ApiGetWorkspaceDirRequest) (*WorkspaceDirResponse, *http.Response, error) { var ( localVarHTTPMethod = http.MethodGet localVarPostBody interface{} formFiles []formFile - localVarReturnValue string + localVarReturnValue *WorkspaceDirResponse ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "WorkspaceToolboxAPIService.GetSessionCommandLogs") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "WorkspaceToolboxAPIService.GetWorkspaceDir") if err != nil { return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/workspace/{workspaceId}/{projectId}/toolbox/process/session/{sessionId}/command/{commandId}/logs" + localVarPath := localBasePath + "/workspace/{workspaceId}/toolbox/workspace-dir" localVarPath = strings.Replace(localVarPath, "{"+"workspaceId"+"}", url.PathEscape(parameterValueToString(r.workspaceId, "workspaceId")), -1) - localVarPath = strings.Replace(localVarPath, "{"+"projectId"+"}", url.PathEscape(parameterValueToString(r.projectId, "projectId")), -1) - localVarPath = strings.Replace(localVarPath, "{"+"sessionId"+"}", url.PathEscape(parameterValueToString(r.sessionId, "sessionId")), -1) - localVarPath = strings.Replace(localVarPath, "{"+"commandId"+"}", url.PathEscape(parameterValueToString(r.commandId, "commandId")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -1956,7 +1896,7 @@ func (a *WorkspaceToolboxAPIService) GetSessionCommandLogsExecute(r ApiGetSessio } // to determine the Accept header - localVarHTTPHeaderAccepts := []string{"*/*"} + localVarHTTPHeaderAccepts := []string{"application/json"} // set Accept header localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) @@ -2018,7 +1958,6 @@ type ApiGitAddFilesRequest struct { ctx context.Context ApiService *WorkspaceToolboxAPIService workspaceId string - projectId string params *GitAddRequest } @@ -2039,15 +1978,13 @@ Add files to git commit @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @param workspaceId Workspace ID or Name - @param projectId Project ID @return ApiGitAddFilesRequest */ -func (a *WorkspaceToolboxAPIService) GitAddFiles(ctx context.Context, workspaceId string, projectId string) ApiGitAddFilesRequest { +func (a *WorkspaceToolboxAPIService) GitAddFiles(ctx context.Context, workspaceId string) ApiGitAddFilesRequest { return ApiGitAddFilesRequest{ ApiService: a, ctx: ctx, workspaceId: workspaceId, - projectId: projectId, } } @@ -2064,9 +2001,8 @@ func (a *WorkspaceToolboxAPIService) GitAddFilesExecute(r ApiGitAddFilesRequest) return nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/workspace/{workspaceId}/{projectId}/toolbox/git/add" + localVarPath := localBasePath + "/workspace/{workspaceId}/toolbox/git/add" localVarPath = strings.Replace(localVarPath, "{"+"workspaceId"+"}", url.PathEscape(parameterValueToString(r.workspaceId, "workspaceId")), -1) - localVarPath = strings.Replace(localVarPath, "{"+"projectId"+"}", url.PathEscape(parameterValueToString(r.projectId, "projectId")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -2140,7 +2076,6 @@ type ApiGitBranchListRequest struct { ctx context.Context ApiService *WorkspaceToolboxAPIService workspaceId string - projectId string path *string } @@ -2157,19 +2092,17 @@ func (r ApiGitBranchListRequest) Execute() (*ListBranchResponse, *http.Response, /* GitBranchList Get branch list -Get branch list from git repository inside workspace project +Get branch list from git repository inside a workspace @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @param workspaceId Workspace ID or Name - @param projectId Project ID @return ApiGitBranchListRequest */ -func (a *WorkspaceToolboxAPIService) GitBranchList(ctx context.Context, workspaceId string, projectId string) ApiGitBranchListRequest { +func (a *WorkspaceToolboxAPIService) GitBranchList(ctx context.Context, workspaceId string) ApiGitBranchListRequest { return ApiGitBranchListRequest{ ApiService: a, ctx: ctx, workspaceId: workspaceId, - projectId: projectId, } } @@ -2189,9 +2122,8 @@ func (a *WorkspaceToolboxAPIService) GitBranchListExecute(r ApiGitBranchListRequ return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/workspace/{workspaceId}/{projectId}/toolbox/git/branches" + localVarPath := localBasePath + "/workspace/{workspaceId}/toolbox/git/branches" localVarPath = strings.Replace(localVarPath, "{"+"workspaceId"+"}", url.PathEscape(parameterValueToString(r.workspaceId, "workspaceId")), -1) - localVarPath = strings.Replace(localVarPath, "{"+"projectId"+"}", url.PathEscape(parameterValueToString(r.projectId, "projectId")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -2273,7 +2205,6 @@ type ApiGitCloneRepositoryRequest struct { ctx context.Context ApiService *WorkspaceToolboxAPIService workspaceId string - projectId string params *GitCloneRequest } @@ -2290,19 +2221,17 @@ func (r ApiGitCloneRepositoryRequest) Execute() (*http.Response, error) { /* GitCloneRepository Clone git repository -Clone git repository inside workspace project +Clone git repository inside a workspace @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @param workspaceId Workspace ID or Name - @param projectId Project ID @return ApiGitCloneRepositoryRequest */ -func (a *WorkspaceToolboxAPIService) GitCloneRepository(ctx context.Context, workspaceId string, projectId string) ApiGitCloneRepositoryRequest { +func (a *WorkspaceToolboxAPIService) GitCloneRepository(ctx context.Context, workspaceId string) ApiGitCloneRepositoryRequest { return ApiGitCloneRepositoryRequest{ ApiService: a, ctx: ctx, workspaceId: workspaceId, - projectId: projectId, } } @@ -2319,9 +2248,8 @@ func (a *WorkspaceToolboxAPIService) GitCloneRepositoryExecute(r ApiGitCloneRepo return nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/workspace/{workspaceId}/{projectId}/toolbox/git/clone" + localVarPath := localBasePath + "/workspace/{workspaceId}/toolbox/git/clone" localVarPath = strings.Replace(localVarPath, "{"+"workspaceId"+"}", url.PathEscape(parameterValueToString(r.workspaceId, "workspaceId")), -1) - localVarPath = strings.Replace(localVarPath, "{"+"projectId"+"}", url.PathEscape(parameterValueToString(r.projectId, "projectId")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -2395,7 +2323,6 @@ type ApiGitCommitChangesRequest struct { ctx context.Context ApiService *WorkspaceToolboxAPIService workspaceId string - projectId string params *GitCommitRequest } @@ -2412,19 +2339,17 @@ func (r ApiGitCommitChangesRequest) Execute() (*GitCommitResponse, *http.Respons /* GitCommitChanges Commit changes -Commit changes to git repository inside workspace project +Commit changes to git repository inside a workspace @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @param workspaceId Workspace ID or Name - @param projectId Project ID @return ApiGitCommitChangesRequest */ -func (a *WorkspaceToolboxAPIService) GitCommitChanges(ctx context.Context, workspaceId string, projectId string) ApiGitCommitChangesRequest { +func (a *WorkspaceToolboxAPIService) GitCommitChanges(ctx context.Context, workspaceId string) ApiGitCommitChangesRequest { return ApiGitCommitChangesRequest{ ApiService: a, ctx: ctx, workspaceId: workspaceId, - projectId: projectId, } } @@ -2444,9 +2369,8 @@ func (a *WorkspaceToolboxAPIService) GitCommitChangesExecute(r ApiGitCommitChang return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/workspace/{workspaceId}/{projectId}/toolbox/git/commit" + localVarPath := localBasePath + "/workspace/{workspaceId}/toolbox/git/commit" localVarPath = strings.Replace(localVarPath, "{"+"workspaceId"+"}", url.PathEscape(parameterValueToString(r.workspaceId, "workspaceId")), -1) - localVarPath = strings.Replace(localVarPath, "{"+"projectId"+"}", url.PathEscape(parameterValueToString(r.projectId, "projectId")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -2529,7 +2453,6 @@ type ApiGitCommitHistoryRequest struct { ctx context.Context ApiService *WorkspaceToolboxAPIService workspaceId string - projectId string path *string } @@ -2546,19 +2469,17 @@ func (r ApiGitCommitHistoryRequest) Execute() ([]GitCommitInfo, *http.Response, /* GitCommitHistory Get commit history -Get commit history from git repository inside workspace project +Get commit history from git repository inside a workspace @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @param workspaceId Workspace ID or Name - @param projectId Project ID @return ApiGitCommitHistoryRequest */ -func (a *WorkspaceToolboxAPIService) GitCommitHistory(ctx context.Context, workspaceId string, projectId string) ApiGitCommitHistoryRequest { +func (a *WorkspaceToolboxAPIService) GitCommitHistory(ctx context.Context, workspaceId string) ApiGitCommitHistoryRequest { return ApiGitCommitHistoryRequest{ ApiService: a, ctx: ctx, workspaceId: workspaceId, - projectId: projectId, } } @@ -2578,9 +2499,8 @@ func (a *WorkspaceToolboxAPIService) GitCommitHistoryExecute(r ApiGitCommitHisto return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/workspace/{workspaceId}/{projectId}/toolbox/git/history" + localVarPath := localBasePath + "/workspace/{workspaceId}/toolbox/git/history" localVarPath = strings.Replace(localVarPath, "{"+"workspaceId"+"}", url.PathEscape(parameterValueToString(r.workspaceId, "workspaceId")), -1) - localVarPath = strings.Replace(localVarPath, "{"+"projectId"+"}", url.PathEscape(parameterValueToString(r.projectId, "projectId")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -2662,7 +2582,6 @@ type ApiGitCreateBranchRequest struct { ctx context.Context ApiService *WorkspaceToolboxAPIService workspaceId string - projectId string params *GitBranchRequest } @@ -2679,19 +2598,17 @@ func (r ApiGitCreateBranchRequest) Execute() (*http.Response, error) { /* GitCreateBranch Create branch -Create branch on git repository inside workspace project +Create branch on git repository inside a workspace @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @param workspaceId Workspace ID or Name - @param projectId Project ID @return ApiGitCreateBranchRequest */ -func (a *WorkspaceToolboxAPIService) GitCreateBranch(ctx context.Context, workspaceId string, projectId string) ApiGitCreateBranchRequest { +func (a *WorkspaceToolboxAPIService) GitCreateBranch(ctx context.Context, workspaceId string) ApiGitCreateBranchRequest { return ApiGitCreateBranchRequest{ ApiService: a, ctx: ctx, workspaceId: workspaceId, - projectId: projectId, } } @@ -2708,9 +2625,8 @@ func (a *WorkspaceToolboxAPIService) GitCreateBranchExecute(r ApiGitCreateBranch return nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/workspace/{workspaceId}/{projectId}/toolbox/git/branches" + localVarPath := localBasePath + "/workspace/{workspaceId}/toolbox/git/branches" localVarPath = strings.Replace(localVarPath, "{"+"workspaceId"+"}", url.PathEscape(parameterValueToString(r.workspaceId, "workspaceId")), -1) - localVarPath = strings.Replace(localVarPath, "{"+"projectId"+"}", url.PathEscape(parameterValueToString(r.projectId, "projectId")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -2784,7 +2700,6 @@ type ApiGitGitStatusRequest struct { ctx context.Context ApiService *WorkspaceToolboxAPIService workspaceId string - projectId string path *string } @@ -2801,19 +2716,17 @@ func (r ApiGitGitStatusRequest) Execute() (*GitStatus, *http.Response, error) { /* GitGitStatus Get git status -Get status from git repository inside workspace project +Get status from git repository inside a workspace @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @param workspaceId Workspace ID or Name - @param projectId Project ID @return ApiGitGitStatusRequest */ -func (a *WorkspaceToolboxAPIService) GitGitStatus(ctx context.Context, workspaceId string, projectId string) ApiGitGitStatusRequest { +func (a *WorkspaceToolboxAPIService) GitGitStatus(ctx context.Context, workspaceId string) ApiGitGitStatusRequest { return ApiGitGitStatusRequest{ ApiService: a, ctx: ctx, workspaceId: workspaceId, - projectId: projectId, } } @@ -2833,9 +2746,8 @@ func (a *WorkspaceToolboxAPIService) GitGitStatusExecute(r ApiGitGitStatusReques return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/workspace/{workspaceId}/{projectId}/toolbox/git/status" + localVarPath := localBasePath + "/workspace/{workspaceId}/toolbox/git/status" localVarPath = strings.Replace(localVarPath, "{"+"workspaceId"+"}", url.PathEscape(parameterValueToString(r.workspaceId, "workspaceId")), -1) - localVarPath = strings.Replace(localVarPath, "{"+"projectId"+"}", url.PathEscape(parameterValueToString(r.projectId, "projectId")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -2917,7 +2829,6 @@ type ApiGitPullChangesRequest struct { ctx context.Context ApiService *WorkspaceToolboxAPIService workspaceId string - projectId string params *GitRepoRequest } @@ -2934,19 +2845,17 @@ func (r ApiGitPullChangesRequest) Execute() (*http.Response, error) { /* GitPullChanges Pull changes -Pull changes from remote to git repository inside workspace project +Pull changes from remote to git repository inside a workspace @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @param workspaceId Workspace ID or Name - @param projectId Project ID @return ApiGitPullChangesRequest */ -func (a *WorkspaceToolboxAPIService) GitPullChanges(ctx context.Context, workspaceId string, projectId string) ApiGitPullChangesRequest { +func (a *WorkspaceToolboxAPIService) GitPullChanges(ctx context.Context, workspaceId string) ApiGitPullChangesRequest { return ApiGitPullChangesRequest{ ApiService: a, ctx: ctx, workspaceId: workspaceId, - projectId: projectId, } } @@ -2963,9 +2872,8 @@ func (a *WorkspaceToolboxAPIService) GitPullChangesExecute(r ApiGitPullChangesRe return nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/workspace/{workspaceId}/{projectId}/toolbox/git/pull" + localVarPath := localBasePath + "/workspace/{workspaceId}/toolbox/git/pull" localVarPath = strings.Replace(localVarPath, "{"+"workspaceId"+"}", url.PathEscape(parameterValueToString(r.workspaceId, "workspaceId")), -1) - localVarPath = strings.Replace(localVarPath, "{"+"projectId"+"}", url.PathEscape(parameterValueToString(r.projectId, "projectId")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -3039,7 +2947,6 @@ type ApiGitPushChangesRequest struct { ctx context.Context ApiService *WorkspaceToolboxAPIService workspaceId string - projectId string params *GitRepoRequest } @@ -3056,19 +2963,17 @@ func (r ApiGitPushChangesRequest) Execute() (*http.Response, error) { /* GitPushChanges Push changes -Push changes to remote from git repository inside workspace project +Push changes to remote from git repository inside a workspace @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @param workspaceId Workspace ID or Name - @param projectId Project ID @return ApiGitPushChangesRequest */ -func (a *WorkspaceToolboxAPIService) GitPushChanges(ctx context.Context, workspaceId string, projectId string) ApiGitPushChangesRequest { +func (a *WorkspaceToolboxAPIService) GitPushChanges(ctx context.Context, workspaceId string) ApiGitPushChangesRequest { return ApiGitPushChangesRequest{ ApiService: a, ctx: ctx, workspaceId: workspaceId, - projectId: projectId, } } @@ -3085,9 +2990,8 @@ func (a *WorkspaceToolboxAPIService) GitPushChangesExecute(r ApiGitPushChangesRe return nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/workspace/{workspaceId}/{projectId}/toolbox/git/push" + localVarPath := localBasePath + "/workspace/{workspaceId}/toolbox/git/push" localVarPath = strings.Replace(localVarPath, "{"+"workspaceId"+"}", url.PathEscape(parameterValueToString(r.workspaceId, "workspaceId")), -1) - localVarPath = strings.Replace(localVarPath, "{"+"projectId"+"}", url.PathEscape(parameterValueToString(r.projectId, "projectId")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -3161,7 +3065,6 @@ type ApiListSessionsRequest struct { ctx context.Context ApiService *WorkspaceToolboxAPIService workspaceId string - projectId string } func (r ApiListSessionsRequest) Execute() ([]Session, *http.Response, error) { @@ -3175,15 +3078,13 @@ List sessions inside workspace project @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @param workspaceId Workspace ID or Name - @param projectId Project ID @return ApiListSessionsRequest */ -func (a *WorkspaceToolboxAPIService) ListSessions(ctx context.Context, workspaceId string, projectId string) ApiListSessionsRequest { +func (a *WorkspaceToolboxAPIService) ListSessions(ctx context.Context, workspaceId string) ApiListSessionsRequest { return ApiListSessionsRequest{ ApiService: a, ctx: ctx, workspaceId: workspaceId, - projectId: projectId, } } @@ -3203,9 +3104,8 @@ func (a *WorkspaceToolboxAPIService) ListSessionsExecute(r ApiListSessionsReques return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/workspace/{workspaceId}/{projectId}/toolbox/process/session" + localVarPath := localBasePath + "/workspace/{workspaceId}/toolbox/process/session" localVarPath = strings.Replace(localVarPath, "{"+"workspaceId"+"}", url.PathEscape(parameterValueToString(r.workspaceId, "workspaceId")), -1) - localVarPath = strings.Replace(localVarPath, "{"+"projectId"+"}", url.PathEscape(parameterValueToString(r.projectId, "projectId")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -3283,7 +3183,6 @@ type ApiLspCompletionsRequest struct { ctx context.Context ApiService *WorkspaceToolboxAPIService workspaceId string - projectId string params *LspCompletionParams } @@ -3304,15 +3203,13 @@ The Completion request is sent from the client to the server to compute completi @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @param workspaceId Workspace ID or Name - @param projectId Project ID @return ApiLspCompletionsRequest */ -func (a *WorkspaceToolboxAPIService) LspCompletions(ctx context.Context, workspaceId string, projectId string) ApiLspCompletionsRequest { +func (a *WorkspaceToolboxAPIService) LspCompletions(ctx context.Context, workspaceId string) ApiLspCompletionsRequest { return ApiLspCompletionsRequest{ ApiService: a, ctx: ctx, workspaceId: workspaceId, - projectId: projectId, } } @@ -3332,9 +3229,8 @@ func (a *WorkspaceToolboxAPIService) LspCompletionsExecute(r ApiLspCompletionsRe return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/workspace/{workspaceId}/{projectId}/toolbox/lsp/completions" + localVarPath := localBasePath + "/workspace/{workspaceId}/toolbox/lsp/completions" localVarPath = strings.Replace(localVarPath, "{"+"workspaceId"+"}", url.PathEscape(parameterValueToString(r.workspaceId, "workspaceId")), -1) - localVarPath = strings.Replace(localVarPath, "{"+"projectId"+"}", url.PathEscape(parameterValueToString(r.projectId, "projectId")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -3417,7 +3313,6 @@ type ApiLspDidCloseRequest struct { ctx context.Context ApiService *WorkspaceToolboxAPIService workspaceId string - projectId string params *LspDocumentRequest } @@ -3438,15 +3333,13 @@ The document close notification is sent from the client to the server when the d @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @param workspaceId Workspace ID or Name - @param projectId Project ID @return ApiLspDidCloseRequest */ -func (a *WorkspaceToolboxAPIService) LspDidClose(ctx context.Context, workspaceId string, projectId string) ApiLspDidCloseRequest { +func (a *WorkspaceToolboxAPIService) LspDidClose(ctx context.Context, workspaceId string) ApiLspDidCloseRequest { return ApiLspDidCloseRequest{ ApiService: a, ctx: ctx, workspaceId: workspaceId, - projectId: projectId, } } @@ -3463,9 +3356,8 @@ func (a *WorkspaceToolboxAPIService) LspDidCloseExecute(r ApiLspDidCloseRequest) return nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/workspace/{workspaceId}/{projectId}/toolbox/lsp/did-close" + localVarPath := localBasePath + "/workspace/{workspaceId}/toolbox/lsp/did-close" localVarPath = strings.Replace(localVarPath, "{"+"workspaceId"+"}", url.PathEscape(parameterValueToString(r.workspaceId, "workspaceId")), -1) - localVarPath = strings.Replace(localVarPath, "{"+"projectId"+"}", url.PathEscape(parameterValueToString(r.projectId, "projectId")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -3539,7 +3431,6 @@ type ApiLspDidOpenRequest struct { ctx context.Context ApiService *WorkspaceToolboxAPIService workspaceId string - projectId string params *LspDocumentRequest } @@ -3560,15 +3451,13 @@ The document open notification is sent from the client to the server to signal n @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @param workspaceId Workspace ID or Name - @param projectId Project ID @return ApiLspDidOpenRequest */ -func (a *WorkspaceToolboxAPIService) LspDidOpen(ctx context.Context, workspaceId string, projectId string) ApiLspDidOpenRequest { +func (a *WorkspaceToolboxAPIService) LspDidOpen(ctx context.Context, workspaceId string) ApiLspDidOpenRequest { return ApiLspDidOpenRequest{ ApiService: a, ctx: ctx, workspaceId: workspaceId, - projectId: projectId, } } @@ -3585,9 +3474,8 @@ func (a *WorkspaceToolboxAPIService) LspDidOpenExecute(r ApiLspDidOpenRequest) ( return nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/workspace/{workspaceId}/{projectId}/toolbox/lsp/did-open" + localVarPath := localBasePath + "/workspace/{workspaceId}/toolbox/lsp/did-open" localVarPath = strings.Replace(localVarPath, "{"+"workspaceId"+"}", url.PathEscape(parameterValueToString(r.workspaceId, "workspaceId")), -1) - localVarPath = strings.Replace(localVarPath, "{"+"projectId"+"}", url.PathEscape(parameterValueToString(r.projectId, "projectId")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -3661,7 +3549,6 @@ type ApiLspDocumentSymbolsRequest struct { ctx context.Context ApiService *WorkspaceToolboxAPIService workspaceId string - projectId string languageId *string pathToProject *string uri *string @@ -3696,15 +3583,13 @@ The document symbol request is sent from the client to the server. @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @param workspaceId Workspace ID or Name - @param projectId Project ID @return ApiLspDocumentSymbolsRequest */ -func (a *WorkspaceToolboxAPIService) LspDocumentSymbols(ctx context.Context, workspaceId string, projectId string) ApiLspDocumentSymbolsRequest { +func (a *WorkspaceToolboxAPIService) LspDocumentSymbols(ctx context.Context, workspaceId string) ApiLspDocumentSymbolsRequest { return ApiLspDocumentSymbolsRequest{ ApiService: a, ctx: ctx, workspaceId: workspaceId, - projectId: projectId, } } @@ -3724,9 +3609,8 @@ func (a *WorkspaceToolboxAPIService) LspDocumentSymbolsExecute(r ApiLspDocumentS return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/workspace/{workspaceId}/{projectId}/toolbox/lsp/document-symbols" + localVarPath := localBasePath + "/workspace/{workspaceId}/toolbox/lsp/document-symbols" localVarPath = strings.Replace(localVarPath, "{"+"workspaceId"+"}", url.PathEscape(parameterValueToString(r.workspaceId, "workspaceId")), -1) - localVarPath = strings.Replace(localVarPath, "{"+"projectId"+"}", url.PathEscape(parameterValueToString(r.projectId, "projectId")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -3816,7 +3700,6 @@ type ApiLspStartRequest struct { ctx context.Context ApiService *WorkspaceToolboxAPIService workspaceId string - projectId string params *LspServerRequest } @@ -3833,19 +3716,17 @@ func (r ApiLspStartRequest) Execute() (*http.Response, error) { /* LspStart Start Lsp server -Start Lsp server process inside workspace project +Start Lsp server process inside a workspace @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @param workspaceId Workspace ID or Name - @param projectId Project ID @return ApiLspStartRequest */ -func (a *WorkspaceToolboxAPIService) LspStart(ctx context.Context, workspaceId string, projectId string) ApiLspStartRequest { +func (a *WorkspaceToolboxAPIService) LspStart(ctx context.Context, workspaceId string) ApiLspStartRequest { return ApiLspStartRequest{ ApiService: a, ctx: ctx, workspaceId: workspaceId, - projectId: projectId, } } @@ -3862,9 +3743,8 @@ func (a *WorkspaceToolboxAPIService) LspStartExecute(r ApiLspStartRequest) (*htt return nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/workspace/{workspaceId}/{projectId}/toolbox/lsp/start" + localVarPath := localBasePath + "/workspace/{workspaceId}/toolbox/lsp/start" localVarPath = strings.Replace(localVarPath, "{"+"workspaceId"+"}", url.PathEscape(parameterValueToString(r.workspaceId, "workspaceId")), -1) - localVarPath = strings.Replace(localVarPath, "{"+"projectId"+"}", url.PathEscape(parameterValueToString(r.projectId, "projectId")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -3938,7 +3818,6 @@ type ApiLspStopRequest struct { ctx context.Context ApiService *WorkspaceToolboxAPIService workspaceId string - projectId string params *LspServerRequest } @@ -3955,19 +3834,17 @@ func (r ApiLspStopRequest) Execute() (*http.Response, error) { /* LspStop Stop Lsp server -Stop Lsp server process inside workspace project +Stop Lsp server process inside a workspace @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @param workspaceId Workspace ID or Name - @param projectId Project ID @return ApiLspStopRequest */ -func (a *WorkspaceToolboxAPIService) LspStop(ctx context.Context, workspaceId string, projectId string) ApiLspStopRequest { +func (a *WorkspaceToolboxAPIService) LspStop(ctx context.Context, workspaceId string) ApiLspStopRequest { return ApiLspStopRequest{ ApiService: a, ctx: ctx, workspaceId: workspaceId, - projectId: projectId, } } @@ -3984,9 +3861,8 @@ func (a *WorkspaceToolboxAPIService) LspStopExecute(r ApiLspStopRequest) (*http. return nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/workspace/{workspaceId}/{projectId}/toolbox/lsp/stop" + localVarPath := localBasePath + "/workspace/{workspaceId}/toolbox/lsp/stop" localVarPath = strings.Replace(localVarPath, "{"+"workspaceId"+"}", url.PathEscape(parameterValueToString(r.workspaceId, "workspaceId")), -1) - localVarPath = strings.Replace(localVarPath, "{"+"projectId"+"}", url.PathEscape(parameterValueToString(r.projectId, "projectId")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -4060,7 +3936,6 @@ type ApiLspWorkspaceSymbolsRequest struct { ctx context.Context ApiService *WorkspaceToolboxAPIService workspaceId string - projectId string languageId *string pathToProject *string query *string @@ -4095,15 +3970,13 @@ The workspace symbol request is sent from the client to the server to list proje @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @param workspaceId Workspace ID or Name - @param projectId Project ID @return ApiLspWorkspaceSymbolsRequest */ -func (a *WorkspaceToolboxAPIService) LspWorkspaceSymbols(ctx context.Context, workspaceId string, projectId string) ApiLspWorkspaceSymbolsRequest { +func (a *WorkspaceToolboxAPIService) LspWorkspaceSymbols(ctx context.Context, workspaceId string) ApiLspWorkspaceSymbolsRequest { return ApiLspWorkspaceSymbolsRequest{ ApiService: a, ctx: ctx, workspaceId: workspaceId, - projectId: projectId, } } @@ -4123,9 +3996,8 @@ func (a *WorkspaceToolboxAPIService) LspWorkspaceSymbolsExecute(r ApiLspWorkspac return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/workspace/{workspaceId}/{projectId}/toolbox/lsp/workspace-symbols" + localVarPath := localBasePath + "/workspace/{workspaceId}/toolbox/lsp/workspace-symbols" localVarPath = strings.Replace(localVarPath, "{"+"workspaceId"+"}", url.PathEscape(parameterValueToString(r.workspaceId, "workspaceId")), -1) - localVarPath = strings.Replace(localVarPath, "{"+"projectId"+"}", url.PathEscape(parameterValueToString(r.projectId, "projectId")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -4215,7 +4087,6 @@ type ApiProcessExecuteCommandRequest struct { ctx context.Context ApiService *WorkspaceToolboxAPIService workspaceId string - projectId string params *ExecuteRequest } @@ -4232,19 +4103,17 @@ func (r ApiProcessExecuteCommandRequest) Execute() (*ExecuteResponse, *http.Resp /* ProcessExecuteCommand Execute command -Execute command synchronously inside workspace project +Execute command synchronously inside a workspace @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @param workspaceId Workspace ID or Name - @param projectId Project ID @return ApiProcessExecuteCommandRequest */ -func (a *WorkspaceToolboxAPIService) ProcessExecuteCommand(ctx context.Context, workspaceId string, projectId string) ApiProcessExecuteCommandRequest { +func (a *WorkspaceToolboxAPIService) ProcessExecuteCommand(ctx context.Context, workspaceId string) ApiProcessExecuteCommandRequest { return ApiProcessExecuteCommandRequest{ ApiService: a, ctx: ctx, workspaceId: workspaceId, - projectId: projectId, } } @@ -4264,9 +4133,8 @@ func (a *WorkspaceToolboxAPIService) ProcessExecuteCommandExecute(r ApiProcessEx return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/workspace/{workspaceId}/{projectId}/toolbox/process/execute" + localVarPath := localBasePath + "/workspace/{workspaceId}/toolbox/process/execute" localVarPath = strings.Replace(localVarPath, "{"+"workspaceId"+"}", url.PathEscape(parameterValueToString(r.workspaceId, "workspaceId")), -1) - localVarPath = strings.Replace(localVarPath, "{"+"projectId"+"}", url.PathEscape(parameterValueToString(r.projectId, "projectId")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -4349,7 +4217,6 @@ type ApiSessionExecuteCommandRequest struct { ctx context.Context ApiService *WorkspaceToolboxAPIService workspaceId string - projectId string sessionId string params *SessionExecuteRequest } @@ -4371,16 +4238,14 @@ Execute command inside a session inside workspace project @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @param workspaceId Workspace ID or Name - @param projectId Project ID @param sessionId Session ID @return ApiSessionExecuteCommandRequest */ -func (a *WorkspaceToolboxAPIService) SessionExecuteCommand(ctx context.Context, workspaceId string, projectId string, sessionId string) ApiSessionExecuteCommandRequest { +func (a *WorkspaceToolboxAPIService) SessionExecuteCommand(ctx context.Context, workspaceId string, sessionId string) ApiSessionExecuteCommandRequest { return ApiSessionExecuteCommandRequest{ ApiService: a, ctx: ctx, workspaceId: workspaceId, - projectId: projectId, sessionId: sessionId, } } @@ -4401,9 +4266,8 @@ func (a *WorkspaceToolboxAPIService) SessionExecuteCommandExecute(r ApiSessionEx return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/workspace/{workspaceId}/{projectId}/toolbox/process/session/{sessionId}/exec" + localVarPath := localBasePath + "/workspace/{workspaceId}/toolbox/process/session/{sessionId}/exec" localVarPath = strings.Replace(localVarPath, "{"+"workspaceId"+"}", url.PathEscape(parameterValueToString(r.workspaceId, "workspaceId")), -1) - localVarPath = strings.Replace(localVarPath, "{"+"projectId"+"}", url.PathEscape(parameterValueToString(r.projectId, "projectId")), -1) localVarPath = strings.Replace(localVarPath, "{"+"sessionId"+"}", url.PathEscape(parameterValueToString(r.sessionId, "sessionId")), -1) localVarHeaderParams := make(map[string]string) diff --git a/pkg/apiclient/client.go b/pkg/apiclient/client.go index dafbf109ef..03b6cbd9ed 100644 --- a/pkg/apiclient/client.go +++ b/pkg/apiclient/client.go @@ -56,24 +56,30 @@ type APIClient struct { DefaultAPI *DefaultAPIService - GitProviderAPI *GitProviderAPIService + EnvVarAPI *EnvVarAPIService - PrebuildAPI *PrebuildAPIService + GitProviderAPI *GitProviderAPIService - ProfileAPI *ProfileAPIService + JobAPI *JobAPIService - ProjectConfigAPI *ProjectConfigAPIService + PrebuildAPI *PrebuildAPIService ProviderAPI *ProviderAPIService + RunnerAPI *RunnerAPIService + SampleAPI *SampleAPIService ServerAPI *ServerAPIService TargetAPI *TargetAPIService + TargetConfigAPI *TargetConfigAPIService + WorkspaceAPI *WorkspaceAPIService + WorkspaceTemplateAPI *WorkspaceTemplateAPIService + WorkspaceToolboxAPI *WorkspaceToolboxAPIService } @@ -97,15 +103,18 @@ func NewAPIClient(cfg *Configuration) *APIClient { c.BuildAPI = (*BuildAPIService)(&c.common) c.ContainerRegistryAPI = (*ContainerRegistryAPIService)(&c.common) c.DefaultAPI = (*DefaultAPIService)(&c.common) + c.EnvVarAPI = (*EnvVarAPIService)(&c.common) c.GitProviderAPI = (*GitProviderAPIService)(&c.common) + c.JobAPI = (*JobAPIService)(&c.common) c.PrebuildAPI = (*PrebuildAPIService)(&c.common) - c.ProfileAPI = (*ProfileAPIService)(&c.common) - c.ProjectConfigAPI = (*ProjectConfigAPIService)(&c.common) c.ProviderAPI = (*ProviderAPIService)(&c.common) + c.RunnerAPI = (*RunnerAPIService)(&c.common) c.SampleAPI = (*SampleAPIService)(&c.common) c.ServerAPI = (*ServerAPIService)(&c.common) c.TargetAPI = (*TargetAPIService)(&c.common) + c.TargetConfigAPI = (*TargetConfigAPIService)(&c.common) c.WorkspaceAPI = (*WorkspaceAPIService)(&c.common) + c.WorkspaceTemplateAPI = (*WorkspaceTemplateAPIService)(&c.common) c.WorkspaceToolboxAPI = (*WorkspaceToolboxAPIService)(&c.common) return c diff --git a/pkg/apiclient/docs/ApiKeyAPI.md b/pkg/apiclient/docs/ApiKeyAPI.md index 99e12717b5..d9ab2fa437 100644 --- a/pkg/apiclient/docs/ApiKeyAPI.md +++ b/pkg/apiclient/docs/ApiKeyAPI.md @@ -4,17 +4,17 @@ All URIs are relative to *http://localhost:3986* Method | HTTP request | Description ------------- | ------------- | ------------- -[**GenerateApiKey**](ApiKeyAPI.md#GenerateApiKey) | **Post** /apikey/{apiKeyName} | Generate an API key +[**CreateApiKey**](ApiKeyAPI.md#CreateApiKey) | **Post** /apikey/{apiKeyName} | Create an API key +[**DeleteApiKey**](ApiKeyAPI.md#DeleteApiKey) | **Delete** /apikey/{apiKeyName} | Delete API key [**ListClientApiKeys**](ApiKeyAPI.md#ListClientApiKeys) | **Get** /apikey | List API keys -[**RevokeApiKey**](ApiKeyAPI.md#RevokeApiKey) | **Delete** /apikey/{apiKeyName} | Revoke API key -## GenerateApiKey +## CreateApiKey -> string GenerateApiKey(ctx, apiKeyName).Execute() +> string CreateApiKey(ctx, apiKeyName).Execute() -Generate an API key +Create an API key @@ -35,13 +35,13 @@ func main() { configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.ApiKeyAPI.GenerateApiKey(context.Background(), apiKeyName).Execute() + resp, r, err := apiClient.ApiKeyAPI.CreateApiKey(context.Background(), apiKeyName).Execute() if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `ApiKeyAPI.GenerateApiKey``: %v\n", err) + fmt.Fprintf(os.Stderr, "Error when calling `ApiKeyAPI.CreateApiKey``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) } - // response from `GenerateApiKey`: string - fmt.Fprintf(os.Stdout, "Response from `ApiKeyAPI.GenerateApiKey`: %v\n", resp) + // response from `CreateApiKey`: string + fmt.Fprintf(os.Stdout, "Response from `ApiKeyAPI.CreateApiKey`: %v\n", resp) } ``` @@ -55,7 +55,7 @@ Name | Type | Description | Notes ### Other Parameters -Other parameters are passed through a pointer to a apiGenerateApiKeyRequest struct via the builder pattern +Other parameters are passed through a pointer to a apiCreateApiKeyRequest struct via the builder pattern Name | Type | Description | Notes @@ -80,11 +80,11 @@ Name | Type | Description | Notes [[Back to README]](../README.md) -## ListClientApiKeys +## DeleteApiKey -> []ApiKey ListClientApiKeys(ctx).Execute() +> DeleteApiKey(ctx, apiKeyName).Execute() -List API keys +Delete API key @@ -101,31 +101,38 @@ import ( ) func main() { + apiKeyName := "apiKeyName_example" // string | API key name configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.ApiKeyAPI.ListClientApiKeys(context.Background()).Execute() + r, err := apiClient.ApiKeyAPI.DeleteApiKey(context.Background(), apiKeyName).Execute() if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `ApiKeyAPI.ListClientApiKeys``: %v\n", err) + fmt.Fprintf(os.Stderr, "Error when calling `ApiKeyAPI.DeleteApiKey``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) } - // response from `ListClientApiKeys`: []ApiKey - fmt.Fprintf(os.Stdout, "Response from `ApiKeyAPI.ListClientApiKeys`: %v\n", resp) } ``` ### Path Parameters -This endpoint does not need any parameter. + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- +**ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. +**apiKeyName** | **string** | API key name | ### Other Parameters -Other parameters are passed through a pointer to a apiListClientApiKeysRequest struct via the builder pattern +Other parameters are passed through a pointer to a apiDeleteApiKeyRequest struct via the builder pattern + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- ### Return type -[**[]ApiKey**](ApiKey.md) + (empty response body) ### Authorization @@ -134,18 +141,18 @@ Other parameters are passed through a pointer to a apiListClientApiKeysRequest s ### HTTP request headers - **Content-Type**: Not defined -- **Accept**: application/json +- **Accept**: Not defined [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) -## RevokeApiKey +## ListClientApiKeys -> RevokeApiKey(ctx, apiKeyName).Execute() +> []ApiKeyViewDTO ListClientApiKeys(ctx).Execute() -Revoke API key +List API keys @@ -162,38 +169,31 @@ import ( ) func main() { - apiKeyName := "apiKeyName_example" // string | API key name configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - r, err := apiClient.ApiKeyAPI.RevokeApiKey(context.Background(), apiKeyName).Execute() + resp, r, err := apiClient.ApiKeyAPI.ListClientApiKeys(context.Background()).Execute() if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `ApiKeyAPI.RevokeApiKey``: %v\n", err) + fmt.Fprintf(os.Stderr, "Error when calling `ApiKeyAPI.ListClientApiKeys``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) } + // response from `ListClientApiKeys`: []ApiKeyViewDTO + fmt.Fprintf(os.Stdout, "Response from `ApiKeyAPI.ListClientApiKeys`: %v\n", resp) } ``` ### Path Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- -**ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. -**apiKeyName** | **string** | API key name | +This endpoint does not need any parameter. ### Other Parameters -Other parameters are passed through a pointer to a apiRevokeApiKeyRequest struct via the builder pattern - - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- +Other parameters are passed through a pointer to a apiListClientApiKeysRequest struct via the builder pattern ### Return type - (empty response body) +[**[]ApiKeyViewDTO**](ApiKeyViewDTO.md) ### Authorization @@ -202,7 +202,7 @@ Name | Type | Description | Notes ### HTTP request headers - **Content-Type**: Not defined -- **Accept**: Not defined +- **Accept**: application/json [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) diff --git a/pkg/apiclient/docs/ApiKey.md b/pkg/apiclient/docs/ApiKeyViewDTO.md similarity index 53% rename from pkg/apiclient/docs/ApiKey.md rename to pkg/apiclient/docs/ApiKeyViewDTO.md index 46fbd9b5dd..c15444aefc 100644 --- a/pkg/apiclient/docs/ApiKey.md +++ b/pkg/apiclient/docs/ApiKeyViewDTO.md @@ -1,88 +1,88 @@ -# ApiKey +# ApiKeyViewDTO ## Properties Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**KeyHash** | **string** | | -**Name** | **string** | Project or client name | -**Type** | [**ApikeyApiKeyType**](ApikeyApiKeyType.md) | | +**Current** | **bool** | | +**Name** | **string** | | +**Type** | [**ModelsApiKeyType**](ModelsApiKeyType.md) | | ## Methods -### NewApiKey +### NewApiKeyViewDTO -`func NewApiKey(keyHash string, name string, type_ ApikeyApiKeyType, ) *ApiKey` +`func NewApiKeyViewDTO(current bool, name string, type_ ModelsApiKeyType, ) *ApiKeyViewDTO` -NewApiKey instantiates a new ApiKey object +NewApiKeyViewDTO instantiates a new ApiKeyViewDTO object This constructor will assign default values to properties that have it defined, and makes sure properties required by API are set, but the set of arguments will change when the set of required properties is changed -### NewApiKeyWithDefaults +### NewApiKeyViewDTOWithDefaults -`func NewApiKeyWithDefaults() *ApiKey` +`func NewApiKeyViewDTOWithDefaults() *ApiKeyViewDTO` -NewApiKeyWithDefaults instantiates a new ApiKey object +NewApiKeyViewDTOWithDefaults instantiates a new ApiKeyViewDTO object This constructor will only assign default values to properties that have it defined, but it doesn't guarantee that properties required by API are set -### GetKeyHash +### GetCurrent -`func (o *ApiKey) GetKeyHash() string` +`func (o *ApiKeyViewDTO) GetCurrent() bool` -GetKeyHash returns the KeyHash field if non-nil, zero value otherwise. +GetCurrent returns the Current field if non-nil, zero value otherwise. -### GetKeyHashOk +### GetCurrentOk -`func (o *ApiKey) GetKeyHashOk() (*string, bool)` +`func (o *ApiKeyViewDTO) GetCurrentOk() (*bool, bool)` -GetKeyHashOk returns a tuple with the KeyHash field if it's non-nil, zero value otherwise +GetCurrentOk returns a tuple with the Current field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. -### SetKeyHash +### SetCurrent -`func (o *ApiKey) SetKeyHash(v string)` +`func (o *ApiKeyViewDTO) SetCurrent(v bool)` -SetKeyHash sets KeyHash field to given value. +SetCurrent sets Current field to given value. ### GetName -`func (o *ApiKey) GetName() string` +`func (o *ApiKeyViewDTO) GetName() string` GetName returns the Name field if non-nil, zero value otherwise. ### GetNameOk -`func (o *ApiKey) GetNameOk() (*string, bool)` +`func (o *ApiKeyViewDTO) GetNameOk() (*string, bool)` GetNameOk returns a tuple with the Name field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. ### SetName -`func (o *ApiKey) SetName(v string)` +`func (o *ApiKeyViewDTO) SetName(v string)` SetName sets Name field to given value. ### GetType -`func (o *ApiKey) GetType() ApikeyApiKeyType` +`func (o *ApiKeyViewDTO) GetType() ModelsApiKeyType` GetType returns the Type field if non-nil, zero value otherwise. ### GetTypeOk -`func (o *ApiKey) GetTypeOk() (*ApikeyApiKeyType, bool)` +`func (o *ApiKeyViewDTO) GetTypeOk() (*ModelsApiKeyType, bool)` GetTypeOk returns a tuple with the Type field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. ### SetType -`func (o *ApiKey) SetType(v ApikeyApiKeyType)` +`func (o *ApiKeyViewDTO) SetType(v ModelsApiKeyType)` SetType sets Type field to given value. diff --git a/pkg/apiclient/docs/BuildAPI.md b/pkg/apiclient/docs/BuildAPI.md index 8c001f7e96..893f4a9c1c 100644 --- a/pkg/apiclient/docs/BuildAPI.md +++ b/pkg/apiclient/docs/BuildAPI.md @@ -8,8 +8,9 @@ Method | HTTP request | Description [**DeleteAllBuilds**](BuildAPI.md#DeleteAllBuilds) | **Delete** /build | Delete ALL builds [**DeleteBuild**](BuildAPI.md#DeleteBuild) | **Delete** /build/{buildId} | Delete build [**DeleteBuildsFromPrebuild**](BuildAPI.md#DeleteBuildsFromPrebuild) | **Delete** /build/prebuild/{prebuildId} | Delete builds -[**GetBuild**](BuildAPI.md#GetBuild) | **Get** /build/{buildId} | Get build data +[**FindBuild**](BuildAPI.md#FindBuild) | **Get** /build/{buildId} | Find build [**ListBuilds**](BuildAPI.md#ListBuilds) | **Get** /build | List builds +[**ListSuccessfulBuilds**](BuildAPI.md#ListSuccessfulBuilds) | **Get** /build/successful/{repoUrl} | List successful builds for Git repository @@ -34,7 +35,7 @@ import ( ) func main() { - createBuildDto := *openapiclient.NewCreateBuildDTO("Branch_example", map[string]string{"key": "Inner_example"}, "ProjectConfigName_example") // CreateBuildDTO | Create Build DTO + createBuildDto := *openapiclient.NewCreateBuildDTO("Branch_example", map[string]string{"key": "Inner_example"}, "WorkspaceTemplateName_example") // CreateBuildDTO | Create Build DTO configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) @@ -283,11 +284,11 @@ Name | Type | Description | Notes [[Back to README]](../README.md) -## GetBuild +## FindBuild -> Build GetBuild(ctx, buildId).Execute() +> BuildDTO FindBuild(ctx, buildId).Execute() -Get build data +Find build @@ -308,13 +309,13 @@ func main() { configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.BuildAPI.GetBuild(context.Background(), buildId).Execute() + resp, r, err := apiClient.BuildAPI.FindBuild(context.Background(), buildId).Execute() if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `BuildAPI.GetBuild``: %v\n", err) + fmt.Fprintf(os.Stderr, "Error when calling `BuildAPI.FindBuild``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) } - // response from `GetBuild`: Build - fmt.Fprintf(os.Stdout, "Response from `BuildAPI.GetBuild`: %v\n", resp) + // response from `FindBuild`: BuildDTO + fmt.Fprintf(os.Stdout, "Response from `BuildAPI.FindBuild`: %v\n", resp) } ``` @@ -328,7 +329,7 @@ Name | Type | Description | Notes ### Other Parameters -Other parameters are passed through a pointer to a apiGetBuildRequest struct via the builder pattern +Other parameters are passed through a pointer to a apiFindBuildRequest struct via the builder pattern Name | Type | Description | Notes @@ -337,7 +338,7 @@ Name | Type | Description | Notes ### Return type -[**Build**](Build.md) +[**BuildDTO**](BuildDTO.md) ### Authorization @@ -355,7 +356,7 @@ Name | Type | Description | Notes ## ListBuilds -> []Build ListBuilds(ctx).Execute() +> []BuildDTO ListBuilds(ctx).Execute() List builds @@ -382,7 +383,7 @@ func main() { fmt.Fprintf(os.Stderr, "Error when calling `BuildAPI.ListBuilds``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) } - // response from `ListBuilds`: []Build + // response from `ListBuilds`: []BuildDTO fmt.Fprintf(os.Stdout, "Response from `BuildAPI.ListBuilds`: %v\n", resp) } ``` @@ -398,7 +399,77 @@ Other parameters are passed through a pointer to a apiListBuildsRequest struct v ### Return type -[**[]Build**](Build.md) +[**[]BuildDTO**](BuildDTO.md) + +### Authorization + +[Bearer](../README.md#Bearer) + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) +[[Back to Model list]](../README.md#documentation-for-models) +[[Back to README]](../README.md) + + +## ListSuccessfulBuilds + +> []BuildDTO ListSuccessfulBuilds(ctx, repoUrl).Execute() + +List successful builds for Git repository + + + +### Example + +```go +package main + +import ( + "context" + "fmt" + "os" + openapiclient "github.com/GIT_USER_ID/GIT_REPO_ID/apiclient" +) + +func main() { + repoUrl := "repoUrl_example" // string | Repository URL + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.BuildAPI.ListSuccessfulBuilds(context.Background(), repoUrl).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `BuildAPI.ListSuccessfulBuilds``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `ListSuccessfulBuilds`: []BuildDTO + fmt.Fprintf(os.Stdout, "Response from `BuildAPI.ListSuccessfulBuilds`: %v\n", resp) +} +``` + +### Path Parameters + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- +**ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. +**repoUrl** | **string** | Repository URL | + +### Other Parameters + +Other parameters are passed through a pointer to a apiListSuccessfulBuildsRequest struct via the builder pattern + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + + +### Return type + +[**[]BuildDTO**](BuildDTO.md) ### Authorization diff --git a/pkg/apiclient/docs/BuildBuildState.md b/pkg/apiclient/docs/BuildBuildState.md deleted file mode 100644 index 8a8b6a9b71..0000000000 --- a/pkg/apiclient/docs/BuildBuildState.md +++ /dev/null @@ -1,25 +0,0 @@ -# BuildBuildState - -## Enum - - -* `BuildStatePendingRun` (value: `"pending-run"`) - -* `BuildStateRunning` (value: `"running"`) - -* `BuildStateError` (value: `"error"`) - -* `BuildStateSuccess` (value: `"success"`) - -* `BuildStatePublished` (value: `"published"`) - -* `BuildStatePendingDelete` (value: `"pending-delete"`) - -* `BuildStatePendingForcedDelete` (value: `"pending-forced-delete"`) - -* `BuildStateDeleting` (value: `"deleting"`) - - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/pkg/apiclient/docs/Build.md b/pkg/apiclient/docs/BuildDTO.md similarity index 57% rename from pkg/apiclient/docs/Build.md rename to pkg/apiclient/docs/BuildDTO.md index e020561cf3..f25122e17c 100644 --- a/pkg/apiclient/docs/Build.md +++ b/pkg/apiclient/docs/BuildDTO.md @@ -1,4 +1,4 @@ -# Build +# BuildDTO ## Properties @@ -10,263 +10,320 @@ Name | Type | Description | Notes **EnvVars** | **map[string]string** | | **Id** | **string** | | **Image** | Pointer to **string** | | [optional] -**PrebuildId** | **string** | | +**LastJob** | Pointer to [**Job**](Job.md) | | [optional] +**LastJobId** | Pointer to **string** | | [optional] +**PrebuildId** | Pointer to **string** | | [optional] **Repository** | [**GitRepository**](GitRepository.md) | | -**State** | [**BuildBuildState**](BuildBuildState.md) | | +**State** | [**ResourceState**](ResourceState.md) | | **UpdatedAt** | **string** | | **User** | Pointer to **string** | | [optional] ## Methods -### NewBuild +### NewBuildDTO -`func NewBuild(containerConfig ContainerConfig, createdAt string, envVars map[string]string, id string, prebuildId string, repository GitRepository, state BuildBuildState, updatedAt string, ) *Build` +`func NewBuildDTO(containerConfig ContainerConfig, createdAt string, envVars map[string]string, id string, repository GitRepository, state ResourceState, updatedAt string, ) *BuildDTO` -NewBuild instantiates a new Build object +NewBuildDTO instantiates a new BuildDTO object This constructor will assign default values to properties that have it defined, and makes sure properties required by API are set, but the set of arguments will change when the set of required properties is changed -### NewBuildWithDefaults +### NewBuildDTOWithDefaults -`func NewBuildWithDefaults() *Build` +`func NewBuildDTOWithDefaults() *BuildDTO` -NewBuildWithDefaults instantiates a new Build object +NewBuildDTOWithDefaults instantiates a new BuildDTO object This constructor will only assign default values to properties that have it defined, but it doesn't guarantee that properties required by API are set ### GetBuildConfig -`func (o *Build) GetBuildConfig() BuildConfig` +`func (o *BuildDTO) GetBuildConfig() BuildConfig` GetBuildConfig returns the BuildConfig field if non-nil, zero value otherwise. ### GetBuildConfigOk -`func (o *Build) GetBuildConfigOk() (*BuildConfig, bool)` +`func (o *BuildDTO) GetBuildConfigOk() (*BuildConfig, bool)` GetBuildConfigOk returns a tuple with the BuildConfig field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. ### SetBuildConfig -`func (o *Build) SetBuildConfig(v BuildConfig)` +`func (o *BuildDTO) SetBuildConfig(v BuildConfig)` SetBuildConfig sets BuildConfig field to given value. ### HasBuildConfig -`func (o *Build) HasBuildConfig() bool` +`func (o *BuildDTO) HasBuildConfig() bool` HasBuildConfig returns a boolean if a field has been set. ### GetContainerConfig -`func (o *Build) GetContainerConfig() ContainerConfig` +`func (o *BuildDTO) GetContainerConfig() ContainerConfig` GetContainerConfig returns the ContainerConfig field if non-nil, zero value otherwise. ### GetContainerConfigOk -`func (o *Build) GetContainerConfigOk() (*ContainerConfig, bool)` +`func (o *BuildDTO) GetContainerConfigOk() (*ContainerConfig, bool)` GetContainerConfigOk returns a tuple with the ContainerConfig field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. ### SetContainerConfig -`func (o *Build) SetContainerConfig(v ContainerConfig)` +`func (o *BuildDTO) SetContainerConfig(v ContainerConfig)` SetContainerConfig sets ContainerConfig field to given value. ### GetCreatedAt -`func (o *Build) GetCreatedAt() string` +`func (o *BuildDTO) GetCreatedAt() string` GetCreatedAt returns the CreatedAt field if non-nil, zero value otherwise. ### GetCreatedAtOk -`func (o *Build) GetCreatedAtOk() (*string, bool)` +`func (o *BuildDTO) GetCreatedAtOk() (*string, bool)` GetCreatedAtOk returns a tuple with the CreatedAt field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. ### SetCreatedAt -`func (o *Build) SetCreatedAt(v string)` +`func (o *BuildDTO) SetCreatedAt(v string)` SetCreatedAt sets CreatedAt field to given value. ### GetEnvVars -`func (o *Build) GetEnvVars() map[string]string` +`func (o *BuildDTO) GetEnvVars() map[string]string` GetEnvVars returns the EnvVars field if non-nil, zero value otherwise. ### GetEnvVarsOk -`func (o *Build) GetEnvVarsOk() (*map[string]string, bool)` +`func (o *BuildDTO) GetEnvVarsOk() (*map[string]string, bool)` GetEnvVarsOk returns a tuple with the EnvVars field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. ### SetEnvVars -`func (o *Build) SetEnvVars(v map[string]string)` +`func (o *BuildDTO) SetEnvVars(v map[string]string)` SetEnvVars sets EnvVars field to given value. ### GetId -`func (o *Build) GetId() string` +`func (o *BuildDTO) GetId() string` GetId returns the Id field if non-nil, zero value otherwise. ### GetIdOk -`func (o *Build) GetIdOk() (*string, bool)` +`func (o *BuildDTO) GetIdOk() (*string, bool)` GetIdOk returns a tuple with the Id field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. ### SetId -`func (o *Build) SetId(v string)` +`func (o *BuildDTO) SetId(v string)` SetId sets Id field to given value. ### GetImage -`func (o *Build) GetImage() string` +`func (o *BuildDTO) GetImage() string` GetImage returns the Image field if non-nil, zero value otherwise. ### GetImageOk -`func (o *Build) GetImageOk() (*string, bool)` +`func (o *BuildDTO) GetImageOk() (*string, bool)` GetImageOk returns a tuple with the Image field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. ### SetImage -`func (o *Build) SetImage(v string)` +`func (o *BuildDTO) SetImage(v string)` SetImage sets Image field to given value. ### HasImage -`func (o *Build) HasImage() bool` +`func (o *BuildDTO) HasImage() bool` HasImage returns a boolean if a field has been set. +### GetLastJob + +`func (o *BuildDTO) GetLastJob() Job` + +GetLastJob returns the LastJob field if non-nil, zero value otherwise. + +### GetLastJobOk + +`func (o *BuildDTO) GetLastJobOk() (*Job, bool)` + +GetLastJobOk returns a tuple with the LastJob field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetLastJob + +`func (o *BuildDTO) SetLastJob(v Job)` + +SetLastJob sets LastJob field to given value. + +### HasLastJob + +`func (o *BuildDTO) HasLastJob() bool` + +HasLastJob returns a boolean if a field has been set. + +### GetLastJobId + +`func (o *BuildDTO) GetLastJobId() string` + +GetLastJobId returns the LastJobId field if non-nil, zero value otherwise. + +### GetLastJobIdOk + +`func (o *BuildDTO) GetLastJobIdOk() (*string, bool)` + +GetLastJobIdOk returns a tuple with the LastJobId field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetLastJobId + +`func (o *BuildDTO) SetLastJobId(v string)` + +SetLastJobId sets LastJobId field to given value. + +### HasLastJobId + +`func (o *BuildDTO) HasLastJobId() bool` + +HasLastJobId returns a boolean if a field has been set. + ### GetPrebuildId -`func (o *Build) GetPrebuildId() string` +`func (o *BuildDTO) GetPrebuildId() string` GetPrebuildId returns the PrebuildId field if non-nil, zero value otherwise. ### GetPrebuildIdOk -`func (o *Build) GetPrebuildIdOk() (*string, bool)` +`func (o *BuildDTO) GetPrebuildIdOk() (*string, bool)` GetPrebuildIdOk returns a tuple with the PrebuildId field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. ### SetPrebuildId -`func (o *Build) SetPrebuildId(v string)` +`func (o *BuildDTO) SetPrebuildId(v string)` SetPrebuildId sets PrebuildId field to given value. +### HasPrebuildId + +`func (o *BuildDTO) HasPrebuildId() bool` + +HasPrebuildId returns a boolean if a field has been set. ### GetRepository -`func (o *Build) GetRepository() GitRepository` +`func (o *BuildDTO) GetRepository() GitRepository` GetRepository returns the Repository field if non-nil, zero value otherwise. ### GetRepositoryOk -`func (o *Build) GetRepositoryOk() (*GitRepository, bool)` +`func (o *BuildDTO) GetRepositoryOk() (*GitRepository, bool)` GetRepositoryOk returns a tuple with the Repository field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. ### SetRepository -`func (o *Build) SetRepository(v GitRepository)` +`func (o *BuildDTO) SetRepository(v GitRepository)` SetRepository sets Repository field to given value. ### GetState -`func (o *Build) GetState() BuildBuildState` +`func (o *BuildDTO) GetState() ResourceState` GetState returns the State field if non-nil, zero value otherwise. ### GetStateOk -`func (o *Build) GetStateOk() (*BuildBuildState, bool)` +`func (o *BuildDTO) GetStateOk() (*ResourceState, bool)` GetStateOk returns a tuple with the State field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. ### SetState -`func (o *Build) SetState(v BuildBuildState)` +`func (o *BuildDTO) SetState(v ResourceState)` SetState sets State field to given value. ### GetUpdatedAt -`func (o *Build) GetUpdatedAt() string` +`func (o *BuildDTO) GetUpdatedAt() string` GetUpdatedAt returns the UpdatedAt field if non-nil, zero value otherwise. ### GetUpdatedAtOk -`func (o *Build) GetUpdatedAtOk() (*string, bool)` +`func (o *BuildDTO) GetUpdatedAtOk() (*string, bool)` GetUpdatedAtOk returns a tuple with the UpdatedAt field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. ### SetUpdatedAt -`func (o *Build) SetUpdatedAt(v string)` +`func (o *BuildDTO) SetUpdatedAt(v string)` SetUpdatedAt sets UpdatedAt field to given value. ### GetUser -`func (o *Build) GetUser() string` +`func (o *BuildDTO) GetUser() string` GetUser returns the User field if non-nil, zero value otherwise. ### GetUserOk -`func (o *Build) GetUserOk() (*string, bool)` +`func (o *BuildDTO) GetUserOk() (*string, bool)` GetUserOk returns a tuple with the User field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. ### SetUser -`func (o *Build) SetUser(v string)` +`func (o *BuildDTO) SetUser(v string)` SetUser sets User field to given value. ### HasUser -`func (o *Build) HasUser() bool` +`func (o *BuildDTO) HasUser() bool` HasUser returns a boolean if a field has been set. diff --git a/pkg/apiclient/docs/ContainerRegistryAPI.md b/pkg/apiclient/docs/ContainerRegistryAPI.md index fe3c0dcbd1..12e1792fd1 100644 --- a/pkg/apiclient/docs/ContainerRegistryAPI.md +++ b/pkg/apiclient/docs/ContainerRegistryAPI.md @@ -4,18 +4,15 @@ All URIs are relative to *http://localhost:3986* Method | HTTP request | Description ------------- | ------------- | ------------- -[**GetContainerRegistry**](ContainerRegistryAPI.md#GetContainerRegistry) | **Get** /container-registry/{server} | Get container registry credentials -[**ListContainerRegistries**](ContainerRegistryAPI.md#ListContainerRegistries) | **Get** /container-registry | List container registries -[**RemoveContainerRegistry**](ContainerRegistryAPI.md#RemoveContainerRegistry) | **Delete** /container-registry/{server} | Remove a container registry credentials -[**SetContainerRegistry**](ContainerRegistryAPI.md#SetContainerRegistry) | **Put** /container-registry/{server} | Set container registry credentials +[**FindContainerRegistry**](ContainerRegistryAPI.md#FindContainerRegistry) | **Get** /container-registry/{server} | Find container registry -## GetContainerRegistry +## FindContainerRegistry -> ContainerRegistry GetContainerRegistry(ctx, server).Execute() +> ContainerRegistry FindContainerRegistry(ctx, server).WorkspaceId(workspaceId).Execute() -Get container registry credentials +Find container registry @@ -32,17 +29,18 @@ import ( ) func main() { - server := "server_example" // string | Container Registry server name + server := "server_example" // string | Container registry server + workspaceId := "workspaceId_example" // string | Workspace ID or Name (optional) configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.ContainerRegistryAPI.GetContainerRegistry(context.Background(), server).Execute() + resp, r, err := apiClient.ContainerRegistryAPI.FindContainerRegistry(context.Background(), server).WorkspaceId(workspaceId).Execute() if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `ContainerRegistryAPI.GetContainerRegistry``: %v\n", err) + fmt.Fprintf(os.Stderr, "Error when calling `ContainerRegistryAPI.FindContainerRegistry``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) } - // response from `GetContainerRegistry`: ContainerRegistry - fmt.Fprintf(os.Stdout, "Response from `ContainerRegistryAPI.GetContainerRegistry`: %v\n", resp) + // response from `FindContainerRegistry`: ContainerRegistry + fmt.Fprintf(os.Stdout, "Response from `ContainerRegistryAPI.FindContainerRegistry`: %v\n", resp) } ``` @@ -52,16 +50,17 @@ func main() { Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. -**server** | **string** | Container Registry server name | +**server** | **string** | Container registry server | ### Other Parameters -Other parameters are passed through a pointer to a apiGetContainerRegistryRequest struct via the builder pattern +Other parameters are passed through a pointer to a apiFindContainerRegistryRequest struct via the builder pattern Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- + **workspaceId** | **string** | Workspace ID or Name | ### Return type @@ -80,202 +79,3 @@ Name | Type | Description | Notes [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -## ListContainerRegistries - -> []ContainerRegistry ListContainerRegistries(ctx).Execute() - -List container registries - - - -### Example - -```go -package main - -import ( - "context" - "fmt" - "os" - openapiclient "github.com/GIT_USER_ID/GIT_REPO_ID/apiclient" -) - -func main() { - - configuration := openapiclient.NewConfiguration() - apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.ContainerRegistryAPI.ListContainerRegistries(context.Background()).Execute() - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `ContainerRegistryAPI.ListContainerRegistries``: %v\n", err) - fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - } - // response from `ListContainerRegistries`: []ContainerRegistry - fmt.Fprintf(os.Stdout, "Response from `ContainerRegistryAPI.ListContainerRegistries`: %v\n", resp) -} -``` - -### Path Parameters - -This endpoint does not need any parameter. - -### Other Parameters - -Other parameters are passed through a pointer to a apiListContainerRegistriesRequest struct via the builder pattern - - -### Return type - -[**[]ContainerRegistry**](ContainerRegistry.md) - -### Authorization - -[Bearer](../README.md#Bearer) - -### HTTP request headers - -- **Content-Type**: Not defined -- **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) -[[Back to Model list]](../README.md#documentation-for-models) -[[Back to README]](../README.md) - - -## RemoveContainerRegistry - -> RemoveContainerRegistry(ctx, server).Execute() - -Remove a container registry credentials - - - -### Example - -```go -package main - -import ( - "context" - "fmt" - "os" - openapiclient "github.com/GIT_USER_ID/GIT_REPO_ID/apiclient" -) - -func main() { - server := "server_example" // string | Container Registry server name - - configuration := openapiclient.NewConfiguration() - apiClient := openapiclient.NewAPIClient(configuration) - r, err := apiClient.ContainerRegistryAPI.RemoveContainerRegistry(context.Background(), server).Execute() - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `ContainerRegistryAPI.RemoveContainerRegistry``: %v\n", err) - fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - } -} -``` - -### Path Parameters - - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- -**ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. -**server** | **string** | Container Registry server name | - -### Other Parameters - -Other parameters are passed through a pointer to a apiRemoveContainerRegistryRequest struct via the builder pattern - - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - - -### Return type - - (empty response body) - -### Authorization - -[Bearer](../README.md#Bearer) - -### HTTP request headers - -- **Content-Type**: Not defined -- **Accept**: Not defined - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) -[[Back to Model list]](../README.md#documentation-for-models) -[[Back to README]](../README.md) - - -## SetContainerRegistry - -> SetContainerRegistry(ctx, server).ContainerRegistry(containerRegistry).Execute() - -Set container registry credentials - - - -### Example - -```go -package main - -import ( - "context" - "fmt" - "os" - openapiclient "github.com/GIT_USER_ID/GIT_REPO_ID/apiclient" -) - -func main() { - server := "server_example" // string | Container Registry server name - containerRegistry := *openapiclient.NewContainerRegistry("Password_example", "Server_example", "Username_example") // ContainerRegistry | Container Registry credentials to set - - configuration := openapiclient.NewConfiguration() - apiClient := openapiclient.NewAPIClient(configuration) - r, err := apiClient.ContainerRegistryAPI.SetContainerRegistry(context.Background(), server).ContainerRegistry(containerRegistry).Execute() - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `ContainerRegistryAPI.SetContainerRegistry``: %v\n", err) - fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - } -} -``` - -### Path Parameters - - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- -**ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. -**server** | **string** | Container Registry server name | - -### Other Parameters - -Other parameters are passed through a pointer to a apiSetContainerRegistryRequest struct via the builder pattern - - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - - **containerRegistry** | [**ContainerRegistry**](ContainerRegistry.md) | Container Registry credentials to set | - -### Return type - - (empty response body) - -### Authorization - -[Bearer](../README.md#Bearer) - -### HTTP request headers - -- **Content-Type**: Not defined -- **Accept**: Not defined - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) -[[Back to Model list]](../README.md#documentation-for-models) -[[Back to README]](../README.md) - diff --git a/pkg/apiclient/docs/CreateBuildDTO.md b/pkg/apiclient/docs/CreateBuildDTO.md index f7f23815d4..584888702e 100644 --- a/pkg/apiclient/docs/CreateBuildDTO.md +++ b/pkg/apiclient/docs/CreateBuildDTO.md @@ -7,13 +7,13 @@ Name | Type | Description | Notes **Branch** | **string** | | **EnvVars** | **map[string]string** | | **PrebuildId** | Pointer to **string** | | [optional] -**ProjectConfigName** | **string** | | +**WorkspaceTemplateName** | **string** | | ## Methods ### NewCreateBuildDTO -`func NewCreateBuildDTO(branch string, envVars map[string]string, projectConfigName string, ) *CreateBuildDTO` +`func NewCreateBuildDTO(branch string, envVars map[string]string, workspaceTemplateName string, ) *CreateBuildDTO` NewCreateBuildDTO instantiates a new CreateBuildDTO object This constructor will assign default values to properties that have it defined, @@ -93,24 +93,24 @@ SetPrebuildId sets PrebuildId field to given value. HasPrebuildId returns a boolean if a field has been set. -### GetProjectConfigName +### GetWorkspaceTemplateName -`func (o *CreateBuildDTO) GetProjectConfigName() string` +`func (o *CreateBuildDTO) GetWorkspaceTemplateName() string` -GetProjectConfigName returns the ProjectConfigName field if non-nil, zero value otherwise. +GetWorkspaceTemplateName returns the WorkspaceTemplateName field if non-nil, zero value otherwise. -### GetProjectConfigNameOk +### GetWorkspaceTemplateNameOk -`func (o *CreateBuildDTO) GetProjectConfigNameOk() (*string, bool)` +`func (o *CreateBuildDTO) GetWorkspaceTemplateNameOk() (*string, bool)` -GetProjectConfigNameOk returns a tuple with the ProjectConfigName field if it's non-nil, zero value otherwise +GetWorkspaceTemplateNameOk returns a tuple with the WorkspaceTemplateName field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. -### SetProjectConfigName +### SetWorkspaceTemplateName -`func (o *CreateBuildDTO) SetProjectConfigName(v string)` +`func (o *CreateBuildDTO) SetWorkspaceTemplateName(v string)` -SetProjectConfigName sets ProjectConfigName field to given value. +SetWorkspaceTemplateName sets WorkspaceTemplateName field to given value. diff --git a/pkg/apiclient/docs/CreateProjectDTO.md b/pkg/apiclient/docs/CreateProjectDTO.md deleted file mode 100644 index e084e5a9e5..0000000000 --- a/pkg/apiclient/docs/CreateProjectDTO.md +++ /dev/null @@ -1,197 +0,0 @@ -# CreateProjectDTO - -## Properties - -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**BuildConfig** | Pointer to [**BuildConfig**](BuildConfig.md) | | [optional] -**EnvVars** | **map[string]string** | | -**GitProviderConfigId** | Pointer to **string** | | [optional] -**Image** | Pointer to **string** | | [optional] -**Name** | **string** | | -**Source** | [**CreateProjectSourceDTO**](CreateProjectSourceDTO.md) | | -**User** | Pointer to **string** | | [optional] - -## Methods - -### NewCreateProjectDTO - -`func NewCreateProjectDTO(envVars map[string]string, name string, source CreateProjectSourceDTO, ) *CreateProjectDTO` - -NewCreateProjectDTO instantiates a new CreateProjectDTO object -This constructor will assign default values to properties that have it defined, -and makes sure properties required by API are set, but the set of arguments -will change when the set of required properties is changed - -### NewCreateProjectDTOWithDefaults - -`func NewCreateProjectDTOWithDefaults() *CreateProjectDTO` - -NewCreateProjectDTOWithDefaults instantiates a new CreateProjectDTO object -This constructor will only assign default values to properties that have it defined, -but it doesn't guarantee that properties required by API are set - -### GetBuildConfig - -`func (o *CreateProjectDTO) GetBuildConfig() BuildConfig` - -GetBuildConfig returns the BuildConfig field if non-nil, zero value otherwise. - -### GetBuildConfigOk - -`func (o *CreateProjectDTO) GetBuildConfigOk() (*BuildConfig, bool)` - -GetBuildConfigOk returns a tuple with the BuildConfig field if it's non-nil, zero value otherwise -and a boolean to check if the value has been set. - -### SetBuildConfig - -`func (o *CreateProjectDTO) SetBuildConfig(v BuildConfig)` - -SetBuildConfig sets BuildConfig field to given value. - -### HasBuildConfig - -`func (o *CreateProjectDTO) HasBuildConfig() bool` - -HasBuildConfig returns a boolean if a field has been set. - -### GetEnvVars - -`func (o *CreateProjectDTO) GetEnvVars() map[string]string` - -GetEnvVars returns the EnvVars field if non-nil, zero value otherwise. - -### GetEnvVarsOk - -`func (o *CreateProjectDTO) GetEnvVarsOk() (*map[string]string, bool)` - -GetEnvVarsOk returns a tuple with the EnvVars field if it's non-nil, zero value otherwise -and a boolean to check if the value has been set. - -### SetEnvVars - -`func (o *CreateProjectDTO) SetEnvVars(v map[string]string)` - -SetEnvVars sets EnvVars field to given value. - - -### GetGitProviderConfigId - -`func (o *CreateProjectDTO) GetGitProviderConfigId() string` - -GetGitProviderConfigId returns the GitProviderConfigId field if non-nil, zero value otherwise. - -### GetGitProviderConfigIdOk - -`func (o *CreateProjectDTO) GetGitProviderConfigIdOk() (*string, bool)` - -GetGitProviderConfigIdOk returns a tuple with the GitProviderConfigId field if it's non-nil, zero value otherwise -and a boolean to check if the value has been set. - -### SetGitProviderConfigId - -`func (o *CreateProjectDTO) SetGitProviderConfigId(v string)` - -SetGitProviderConfigId sets GitProviderConfigId field to given value. - -### HasGitProviderConfigId - -`func (o *CreateProjectDTO) HasGitProviderConfigId() bool` - -HasGitProviderConfigId returns a boolean if a field has been set. - -### GetImage - -`func (o *CreateProjectDTO) GetImage() string` - -GetImage returns the Image field if non-nil, zero value otherwise. - -### GetImageOk - -`func (o *CreateProjectDTO) GetImageOk() (*string, bool)` - -GetImageOk returns a tuple with the Image field if it's non-nil, zero value otherwise -and a boolean to check if the value has been set. - -### SetImage - -`func (o *CreateProjectDTO) SetImage(v string)` - -SetImage sets Image field to given value. - -### HasImage - -`func (o *CreateProjectDTO) HasImage() bool` - -HasImage returns a boolean if a field has been set. - -### GetName - -`func (o *CreateProjectDTO) GetName() string` - -GetName returns the Name field if non-nil, zero value otherwise. - -### GetNameOk - -`func (o *CreateProjectDTO) GetNameOk() (*string, bool)` - -GetNameOk returns a tuple with the Name field if it's non-nil, zero value otherwise -and a boolean to check if the value has been set. - -### SetName - -`func (o *CreateProjectDTO) SetName(v string)` - -SetName sets Name field to given value. - - -### GetSource - -`func (o *CreateProjectDTO) GetSource() CreateProjectSourceDTO` - -GetSource returns the Source field if non-nil, zero value otherwise. - -### GetSourceOk - -`func (o *CreateProjectDTO) GetSourceOk() (*CreateProjectSourceDTO, bool)` - -GetSourceOk returns a tuple with the Source field if it's non-nil, zero value otherwise -and a boolean to check if the value has been set. - -### SetSource - -`func (o *CreateProjectDTO) SetSource(v CreateProjectSourceDTO)` - -SetSource sets Source field to given value. - - -### GetUser - -`func (o *CreateProjectDTO) GetUser() string` - -GetUser returns the User field if non-nil, zero value otherwise. - -### GetUserOk - -`func (o *CreateProjectDTO) GetUserOk() (*string, bool)` - -GetUserOk returns a tuple with the User field if it's non-nil, zero value otherwise -and a boolean to check if the value has been set. - -### SetUser - -`func (o *CreateProjectDTO) SetUser(v string)` - -SetUser sets User field to given value. - -### HasUser - -`func (o *CreateProjectDTO) HasUser() bool` - -HasUser returns a boolean if a field has been set. - - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/pkg/apiclient/docs/CreateRunnerDTO.md b/pkg/apiclient/docs/CreateRunnerDTO.md new file mode 100644 index 0000000000..a747e07031 --- /dev/null +++ b/pkg/apiclient/docs/CreateRunnerDTO.md @@ -0,0 +1,72 @@ +# CreateRunnerDTO + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Id** | **string** | | +**Name** | **string** | | + +## Methods + +### NewCreateRunnerDTO + +`func NewCreateRunnerDTO(id string, name string, ) *CreateRunnerDTO` + +NewCreateRunnerDTO instantiates a new CreateRunnerDTO object +This constructor will assign default values to properties that have it defined, +and makes sure properties required by API are set, but the set of arguments +will change when the set of required properties is changed + +### NewCreateRunnerDTOWithDefaults + +`func NewCreateRunnerDTOWithDefaults() *CreateRunnerDTO` + +NewCreateRunnerDTOWithDefaults instantiates a new CreateRunnerDTO object +This constructor will only assign default values to properties that have it defined, +but it doesn't guarantee that properties required by API are set + +### GetId + +`func (o *CreateRunnerDTO) GetId() string` + +GetId returns the Id field if non-nil, zero value otherwise. + +### GetIdOk + +`func (o *CreateRunnerDTO) GetIdOk() (*string, bool)` + +GetIdOk returns a tuple with the Id field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetId + +`func (o *CreateRunnerDTO) SetId(v string)` + +SetId sets Id field to given value. + + +### GetName + +`func (o *CreateRunnerDTO) GetName() string` + +GetName returns the Name field if non-nil, zero value otherwise. + +### GetNameOk + +`func (o *CreateRunnerDTO) GetNameOk() (*string, bool)` + +GetNameOk returns a tuple with the Name field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetName + +`func (o *CreateRunnerDTO) SetName(v string)` + +SetName sets Name field to given value. + + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/pkg/apiclient/docs/CreateRunnerResultDTO.md b/pkg/apiclient/docs/CreateRunnerResultDTO.md new file mode 100644 index 0000000000..eed9a475a0 --- /dev/null +++ b/pkg/apiclient/docs/CreateRunnerResultDTO.md @@ -0,0 +1,119 @@ +# CreateRunnerResultDTO + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**ApiKey** | **string** | | +**Id** | **string** | | +**Metadata** | Pointer to [**RunnerMetadata**](RunnerMetadata.md) | | [optional] +**Name** | **string** | | + +## Methods + +### NewCreateRunnerResultDTO + +`func NewCreateRunnerResultDTO(apiKey string, id string, name string, ) *CreateRunnerResultDTO` + +NewCreateRunnerResultDTO instantiates a new CreateRunnerResultDTO object +This constructor will assign default values to properties that have it defined, +and makes sure properties required by API are set, but the set of arguments +will change when the set of required properties is changed + +### NewCreateRunnerResultDTOWithDefaults + +`func NewCreateRunnerResultDTOWithDefaults() *CreateRunnerResultDTO` + +NewCreateRunnerResultDTOWithDefaults instantiates a new CreateRunnerResultDTO object +This constructor will only assign default values to properties that have it defined, +but it doesn't guarantee that properties required by API are set + +### GetApiKey + +`func (o *CreateRunnerResultDTO) GetApiKey() string` + +GetApiKey returns the ApiKey field if non-nil, zero value otherwise. + +### GetApiKeyOk + +`func (o *CreateRunnerResultDTO) GetApiKeyOk() (*string, bool)` + +GetApiKeyOk returns a tuple with the ApiKey field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetApiKey + +`func (o *CreateRunnerResultDTO) SetApiKey(v string)` + +SetApiKey sets ApiKey field to given value. + + +### GetId + +`func (o *CreateRunnerResultDTO) GetId() string` + +GetId returns the Id field if non-nil, zero value otherwise. + +### GetIdOk + +`func (o *CreateRunnerResultDTO) GetIdOk() (*string, bool)` + +GetIdOk returns a tuple with the Id field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetId + +`func (o *CreateRunnerResultDTO) SetId(v string)` + +SetId sets Id field to given value. + + +### GetMetadata + +`func (o *CreateRunnerResultDTO) GetMetadata() RunnerMetadata` + +GetMetadata returns the Metadata field if non-nil, zero value otherwise. + +### GetMetadataOk + +`func (o *CreateRunnerResultDTO) GetMetadataOk() (*RunnerMetadata, bool)` + +GetMetadataOk returns a tuple with the Metadata field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetMetadata + +`func (o *CreateRunnerResultDTO) SetMetadata(v RunnerMetadata)` + +SetMetadata sets Metadata field to given value. + +### HasMetadata + +`func (o *CreateRunnerResultDTO) HasMetadata() bool` + +HasMetadata returns a boolean if a field has been set. + +### GetName + +`func (o *CreateRunnerResultDTO) GetName() string` + +GetName returns the Name field if non-nil, zero value otherwise. + +### GetNameOk + +`func (o *CreateRunnerResultDTO) GetNameOk() (*string, bool)` + +GetNameOk returns a tuple with the Name field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetName + +`func (o *CreateRunnerResultDTO) SetName(v string)` + +SetName sets Name field to given value. + + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/pkg/apiclient/docs/CreateProviderTargetDTO.md b/pkg/apiclient/docs/CreateTargetConfigDTO.md similarity index 59% rename from pkg/apiclient/docs/CreateProviderTargetDTO.md rename to pkg/apiclient/docs/CreateTargetConfigDTO.md index 87e2ba03a3..96de15581c 100644 --- a/pkg/apiclient/docs/CreateProviderTargetDTO.md +++ b/pkg/apiclient/docs/CreateTargetConfigDTO.md @@ -1,4 +1,4 @@ -# CreateProviderTargetDTO +# CreateTargetConfigDTO ## Properties @@ -6,83 +6,83 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- **Name** | **string** | | **Options** | **string** | | -**ProviderInfo** | [**ProviderProviderInfo**](ProviderProviderInfo.md) | | +**ProviderInfo** | [**ProviderInfo**](ProviderInfo.md) | | ## Methods -### NewCreateProviderTargetDTO +### NewCreateTargetConfigDTO -`func NewCreateProviderTargetDTO(name string, options string, providerInfo ProviderProviderInfo, ) *CreateProviderTargetDTO` +`func NewCreateTargetConfigDTO(name string, options string, providerInfo ProviderInfo, ) *CreateTargetConfigDTO` -NewCreateProviderTargetDTO instantiates a new CreateProviderTargetDTO object +NewCreateTargetConfigDTO instantiates a new CreateTargetConfigDTO object This constructor will assign default values to properties that have it defined, and makes sure properties required by API are set, but the set of arguments will change when the set of required properties is changed -### NewCreateProviderTargetDTOWithDefaults +### NewCreateTargetConfigDTOWithDefaults -`func NewCreateProviderTargetDTOWithDefaults() *CreateProviderTargetDTO` +`func NewCreateTargetConfigDTOWithDefaults() *CreateTargetConfigDTO` -NewCreateProviderTargetDTOWithDefaults instantiates a new CreateProviderTargetDTO object +NewCreateTargetConfigDTOWithDefaults instantiates a new CreateTargetConfigDTO object This constructor will only assign default values to properties that have it defined, but it doesn't guarantee that properties required by API are set ### GetName -`func (o *CreateProviderTargetDTO) GetName() string` +`func (o *CreateTargetConfigDTO) GetName() string` GetName returns the Name field if non-nil, zero value otherwise. ### GetNameOk -`func (o *CreateProviderTargetDTO) GetNameOk() (*string, bool)` +`func (o *CreateTargetConfigDTO) GetNameOk() (*string, bool)` GetNameOk returns a tuple with the Name field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. ### SetName -`func (o *CreateProviderTargetDTO) SetName(v string)` +`func (o *CreateTargetConfigDTO) SetName(v string)` SetName sets Name field to given value. ### GetOptions -`func (o *CreateProviderTargetDTO) GetOptions() string` +`func (o *CreateTargetConfigDTO) GetOptions() string` GetOptions returns the Options field if non-nil, zero value otherwise. ### GetOptionsOk -`func (o *CreateProviderTargetDTO) GetOptionsOk() (*string, bool)` +`func (o *CreateTargetConfigDTO) GetOptionsOk() (*string, bool)` GetOptionsOk returns a tuple with the Options field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. ### SetOptions -`func (o *CreateProviderTargetDTO) SetOptions(v string)` +`func (o *CreateTargetConfigDTO) SetOptions(v string)` SetOptions sets Options field to given value. ### GetProviderInfo -`func (o *CreateProviderTargetDTO) GetProviderInfo() ProviderProviderInfo` +`func (o *CreateTargetConfigDTO) GetProviderInfo() ProviderInfo` GetProviderInfo returns the ProviderInfo field if non-nil, zero value otherwise. ### GetProviderInfoOk -`func (o *CreateProviderTargetDTO) GetProviderInfoOk() (*ProviderProviderInfo, bool)` +`func (o *CreateTargetConfigDTO) GetProviderInfoOk() (*ProviderInfo, bool)` GetProviderInfoOk returns a tuple with the ProviderInfo field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. ### SetProviderInfo -`func (o *CreateProviderTargetDTO) SetProviderInfo(v ProviderProviderInfo)` +`func (o *CreateTargetConfigDTO) SetProviderInfo(v ProviderInfo)` SetProviderInfo sets ProviderInfo field to given value. diff --git a/pkg/apiclient/docs/CreateTargetDTO.md b/pkg/apiclient/docs/CreateTargetDTO.md new file mode 100644 index 0000000000..f9d7f3a668 --- /dev/null +++ b/pkg/apiclient/docs/CreateTargetDTO.md @@ -0,0 +1,93 @@ +# CreateTargetDTO + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Id** | **string** | | +**Name** | **string** | | +**TargetConfigId** | **string** | | + +## Methods + +### NewCreateTargetDTO + +`func NewCreateTargetDTO(id string, name string, targetConfigId string, ) *CreateTargetDTO` + +NewCreateTargetDTO instantiates a new CreateTargetDTO object +This constructor will assign default values to properties that have it defined, +and makes sure properties required by API are set, but the set of arguments +will change when the set of required properties is changed + +### NewCreateTargetDTOWithDefaults + +`func NewCreateTargetDTOWithDefaults() *CreateTargetDTO` + +NewCreateTargetDTOWithDefaults instantiates a new CreateTargetDTO object +This constructor will only assign default values to properties that have it defined, +but it doesn't guarantee that properties required by API are set + +### GetId + +`func (o *CreateTargetDTO) GetId() string` + +GetId returns the Id field if non-nil, zero value otherwise. + +### GetIdOk + +`func (o *CreateTargetDTO) GetIdOk() (*string, bool)` + +GetIdOk returns a tuple with the Id field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetId + +`func (o *CreateTargetDTO) SetId(v string)` + +SetId sets Id field to given value. + + +### GetName + +`func (o *CreateTargetDTO) GetName() string` + +GetName returns the Name field if non-nil, zero value otherwise. + +### GetNameOk + +`func (o *CreateTargetDTO) GetNameOk() (*string, bool)` + +GetNameOk returns a tuple with the Name field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetName + +`func (o *CreateTargetDTO) SetName(v string)` + +SetName sets Name field to given value. + + +### GetTargetConfigId + +`func (o *CreateTargetDTO) GetTargetConfigId() string` + +GetTargetConfigId returns the TargetConfigId field if non-nil, zero value otherwise. + +### GetTargetConfigIdOk + +`func (o *CreateTargetDTO) GetTargetConfigIdOk() (*string, bool)` + +GetTargetConfigIdOk returns a tuple with the TargetConfigId field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetTargetConfigId + +`func (o *CreateTargetDTO) SetTargetConfigId(v string)` + +SetTargetConfigId sets TargetConfigId field to given value. + + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/pkg/apiclient/docs/CreateWorkspaceDTO.md b/pkg/apiclient/docs/CreateWorkspaceDTO.md index 3edfafcb78..6f43c352b2 100644 --- a/pkg/apiclient/docs/CreateWorkspaceDTO.md +++ b/pkg/apiclient/docs/CreateWorkspaceDTO.md @@ -4,16 +4,22 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- +**BuildConfig** | Pointer to [**BuildConfig**](BuildConfig.md) | | [optional] +**EnvVars** | **map[string]string** | | +**GitProviderConfigId** | Pointer to **string** | | [optional] **Id** | **string** | | +**Image** | Pointer to **string** | | [optional] +**Labels** | **map[string]string** | | **Name** | **string** | | -**Projects** | [**[]CreateProjectDTO**](CreateProjectDTO.md) | | -**Target** | **string** | | +**Source** | [**CreateWorkspaceSourceDTO**](CreateWorkspaceSourceDTO.md) | | +**TargetId** | **string** | | +**User** | Pointer to **string** | | [optional] ## Methods ### NewCreateWorkspaceDTO -`func NewCreateWorkspaceDTO(id string, name string, projects []CreateProjectDTO, target string, ) *CreateWorkspaceDTO` +`func NewCreateWorkspaceDTO(envVars map[string]string, id string, labels map[string]string, name string, source CreateWorkspaceSourceDTO, targetId string, ) *CreateWorkspaceDTO` NewCreateWorkspaceDTO instantiates a new CreateWorkspaceDTO object This constructor will assign default values to properties that have it defined, @@ -28,6 +34,76 @@ NewCreateWorkspaceDTOWithDefaults instantiates a new CreateWorkspaceDTO object This constructor will only assign default values to properties that have it defined, but it doesn't guarantee that properties required by API are set +### GetBuildConfig + +`func (o *CreateWorkspaceDTO) GetBuildConfig() BuildConfig` + +GetBuildConfig returns the BuildConfig field if non-nil, zero value otherwise. + +### GetBuildConfigOk + +`func (o *CreateWorkspaceDTO) GetBuildConfigOk() (*BuildConfig, bool)` + +GetBuildConfigOk returns a tuple with the BuildConfig field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetBuildConfig + +`func (o *CreateWorkspaceDTO) SetBuildConfig(v BuildConfig)` + +SetBuildConfig sets BuildConfig field to given value. + +### HasBuildConfig + +`func (o *CreateWorkspaceDTO) HasBuildConfig() bool` + +HasBuildConfig returns a boolean if a field has been set. + +### GetEnvVars + +`func (o *CreateWorkspaceDTO) GetEnvVars() map[string]string` + +GetEnvVars returns the EnvVars field if non-nil, zero value otherwise. + +### GetEnvVarsOk + +`func (o *CreateWorkspaceDTO) GetEnvVarsOk() (*map[string]string, bool)` + +GetEnvVarsOk returns a tuple with the EnvVars field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetEnvVars + +`func (o *CreateWorkspaceDTO) SetEnvVars(v map[string]string)` + +SetEnvVars sets EnvVars field to given value. + + +### GetGitProviderConfigId + +`func (o *CreateWorkspaceDTO) GetGitProviderConfigId() string` + +GetGitProviderConfigId returns the GitProviderConfigId field if non-nil, zero value otherwise. + +### GetGitProviderConfigIdOk + +`func (o *CreateWorkspaceDTO) GetGitProviderConfigIdOk() (*string, bool)` + +GetGitProviderConfigIdOk returns a tuple with the GitProviderConfigId field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetGitProviderConfigId + +`func (o *CreateWorkspaceDTO) SetGitProviderConfigId(v string)` + +SetGitProviderConfigId sets GitProviderConfigId field to given value. + +### HasGitProviderConfigId + +`func (o *CreateWorkspaceDTO) HasGitProviderConfigId() bool` + +HasGitProviderConfigId returns a boolean if a field has been set. + ### GetId `func (o *CreateWorkspaceDTO) GetId() string` @@ -48,6 +124,51 @@ and a boolean to check if the value has been set. SetId sets Id field to given value. +### GetImage + +`func (o *CreateWorkspaceDTO) GetImage() string` + +GetImage returns the Image field if non-nil, zero value otherwise. + +### GetImageOk + +`func (o *CreateWorkspaceDTO) GetImageOk() (*string, bool)` + +GetImageOk returns a tuple with the Image field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetImage + +`func (o *CreateWorkspaceDTO) SetImage(v string)` + +SetImage sets Image field to given value. + +### HasImage + +`func (o *CreateWorkspaceDTO) HasImage() bool` + +HasImage returns a boolean if a field has been set. + +### GetLabels + +`func (o *CreateWorkspaceDTO) GetLabels() map[string]string` + +GetLabels returns the Labels field if non-nil, zero value otherwise. + +### GetLabelsOk + +`func (o *CreateWorkspaceDTO) GetLabelsOk() (*map[string]string, bool)` + +GetLabelsOk returns a tuple with the Labels field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetLabels + +`func (o *CreateWorkspaceDTO) SetLabels(v map[string]string)` + +SetLabels sets Labels field to given value. + + ### GetName `func (o *CreateWorkspaceDTO) GetName() string` @@ -68,45 +189,70 @@ and a boolean to check if the value has been set. SetName sets Name field to given value. -### GetProjects +### GetSource + +`func (o *CreateWorkspaceDTO) GetSource() CreateWorkspaceSourceDTO` + +GetSource returns the Source field if non-nil, zero value otherwise. + +### GetSourceOk + +`func (o *CreateWorkspaceDTO) GetSourceOk() (*CreateWorkspaceSourceDTO, bool)` + +GetSourceOk returns a tuple with the Source field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetSource + +`func (o *CreateWorkspaceDTO) SetSource(v CreateWorkspaceSourceDTO)` + +SetSource sets Source field to given value. -`func (o *CreateWorkspaceDTO) GetProjects() []CreateProjectDTO` -GetProjects returns the Projects field if non-nil, zero value otherwise. +### GetTargetId -### GetProjectsOk +`func (o *CreateWorkspaceDTO) GetTargetId() string` -`func (o *CreateWorkspaceDTO) GetProjectsOk() (*[]CreateProjectDTO, bool)` +GetTargetId returns the TargetId field if non-nil, zero value otherwise. -GetProjectsOk returns a tuple with the Projects field if it's non-nil, zero value otherwise +### GetTargetIdOk + +`func (o *CreateWorkspaceDTO) GetTargetIdOk() (*string, bool)` + +GetTargetIdOk returns a tuple with the TargetId field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. -### SetProjects +### SetTargetId -`func (o *CreateWorkspaceDTO) SetProjects(v []CreateProjectDTO)` +`func (o *CreateWorkspaceDTO) SetTargetId(v string)` -SetProjects sets Projects field to given value. +SetTargetId sets TargetId field to given value. -### GetTarget +### GetUser -`func (o *CreateWorkspaceDTO) GetTarget() string` +`func (o *CreateWorkspaceDTO) GetUser() string` -GetTarget returns the Target field if non-nil, zero value otherwise. +GetUser returns the User field if non-nil, zero value otherwise. -### GetTargetOk +### GetUserOk -`func (o *CreateWorkspaceDTO) GetTargetOk() (*string, bool)` +`func (o *CreateWorkspaceDTO) GetUserOk() (*string, bool)` -GetTargetOk returns a tuple with the Target field if it's non-nil, zero value otherwise +GetUserOk returns a tuple with the User field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. -### SetTarget +### SetUser + +`func (o *CreateWorkspaceDTO) SetUser(v string)` + +SetUser sets User field to given value. -`func (o *CreateWorkspaceDTO) SetTarget(v string)` +### HasUser -SetTarget sets Target field to given value. +`func (o *CreateWorkspaceDTO) HasUser() bool` +HasUser returns a boolean if a field has been set. [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pkg/apiclient/docs/CreateProjectSourceDTO.md b/pkg/apiclient/docs/CreateWorkspaceSourceDTO.md similarity index 62% rename from pkg/apiclient/docs/CreateProjectSourceDTO.md rename to pkg/apiclient/docs/CreateWorkspaceSourceDTO.md index 88591b19f1..3386a801f7 100644 --- a/pkg/apiclient/docs/CreateProjectSourceDTO.md +++ b/pkg/apiclient/docs/CreateWorkspaceSourceDTO.md @@ -1,4 +1,4 @@ -# CreateProjectSourceDTO +# CreateWorkspaceSourceDTO ## Properties @@ -8,39 +8,39 @@ Name | Type | Description | Notes ## Methods -### NewCreateProjectSourceDTO +### NewCreateWorkspaceSourceDTO -`func NewCreateProjectSourceDTO(repository GitRepository, ) *CreateProjectSourceDTO` +`func NewCreateWorkspaceSourceDTO(repository GitRepository, ) *CreateWorkspaceSourceDTO` -NewCreateProjectSourceDTO instantiates a new CreateProjectSourceDTO object +NewCreateWorkspaceSourceDTO instantiates a new CreateWorkspaceSourceDTO object This constructor will assign default values to properties that have it defined, and makes sure properties required by API are set, but the set of arguments will change when the set of required properties is changed -### NewCreateProjectSourceDTOWithDefaults +### NewCreateWorkspaceSourceDTOWithDefaults -`func NewCreateProjectSourceDTOWithDefaults() *CreateProjectSourceDTO` +`func NewCreateWorkspaceSourceDTOWithDefaults() *CreateWorkspaceSourceDTO` -NewCreateProjectSourceDTOWithDefaults instantiates a new CreateProjectSourceDTO object +NewCreateWorkspaceSourceDTOWithDefaults instantiates a new CreateWorkspaceSourceDTO object This constructor will only assign default values to properties that have it defined, but it doesn't guarantee that properties required by API are set ### GetRepository -`func (o *CreateProjectSourceDTO) GetRepository() GitRepository` +`func (o *CreateWorkspaceSourceDTO) GetRepository() GitRepository` GetRepository returns the Repository field if non-nil, zero value otherwise. ### GetRepositoryOk -`func (o *CreateProjectSourceDTO) GetRepositoryOk() (*GitRepository, bool)` +`func (o *CreateWorkspaceSourceDTO) GetRepositoryOk() (*GitRepository, bool)` GetRepositoryOk returns a tuple with the Repository field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. ### SetRepository -`func (o *CreateProjectSourceDTO) SetRepository(v GitRepository)` +`func (o *CreateWorkspaceSourceDTO) SetRepository(v GitRepository)` SetRepository sets Repository field to given value. diff --git a/pkg/apiclient/docs/CreateProjectConfigDTO.md b/pkg/apiclient/docs/CreateWorkspaceTemplateDTO.md similarity index 63% rename from pkg/apiclient/docs/CreateProjectConfigDTO.md rename to pkg/apiclient/docs/CreateWorkspaceTemplateDTO.md index f421b5d580..4e29f37042 100644 --- a/pkg/apiclient/docs/CreateProjectConfigDTO.md +++ b/pkg/apiclient/docs/CreateWorkspaceTemplateDTO.md @@ -1,4 +1,4 @@ -# CreateProjectConfigDTO +# CreateWorkspaceTemplateDTO ## Properties @@ -14,180 +14,180 @@ Name | Type | Description | Notes ## Methods -### NewCreateProjectConfigDTO +### NewCreateWorkspaceTemplateDTO -`func NewCreateProjectConfigDTO(envVars map[string]string, name string, repositoryUrl string, ) *CreateProjectConfigDTO` +`func NewCreateWorkspaceTemplateDTO(envVars map[string]string, name string, repositoryUrl string, ) *CreateWorkspaceTemplateDTO` -NewCreateProjectConfigDTO instantiates a new CreateProjectConfigDTO object +NewCreateWorkspaceTemplateDTO instantiates a new CreateWorkspaceTemplateDTO object This constructor will assign default values to properties that have it defined, and makes sure properties required by API are set, but the set of arguments will change when the set of required properties is changed -### NewCreateProjectConfigDTOWithDefaults +### NewCreateWorkspaceTemplateDTOWithDefaults -`func NewCreateProjectConfigDTOWithDefaults() *CreateProjectConfigDTO` +`func NewCreateWorkspaceTemplateDTOWithDefaults() *CreateWorkspaceTemplateDTO` -NewCreateProjectConfigDTOWithDefaults instantiates a new CreateProjectConfigDTO object +NewCreateWorkspaceTemplateDTOWithDefaults instantiates a new CreateWorkspaceTemplateDTO object This constructor will only assign default values to properties that have it defined, but it doesn't guarantee that properties required by API are set ### GetBuildConfig -`func (o *CreateProjectConfigDTO) GetBuildConfig() BuildConfig` +`func (o *CreateWorkspaceTemplateDTO) GetBuildConfig() BuildConfig` GetBuildConfig returns the BuildConfig field if non-nil, zero value otherwise. ### GetBuildConfigOk -`func (o *CreateProjectConfigDTO) GetBuildConfigOk() (*BuildConfig, bool)` +`func (o *CreateWorkspaceTemplateDTO) GetBuildConfigOk() (*BuildConfig, bool)` GetBuildConfigOk returns a tuple with the BuildConfig field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. ### SetBuildConfig -`func (o *CreateProjectConfigDTO) SetBuildConfig(v BuildConfig)` +`func (o *CreateWorkspaceTemplateDTO) SetBuildConfig(v BuildConfig)` SetBuildConfig sets BuildConfig field to given value. ### HasBuildConfig -`func (o *CreateProjectConfigDTO) HasBuildConfig() bool` +`func (o *CreateWorkspaceTemplateDTO) HasBuildConfig() bool` HasBuildConfig returns a boolean if a field has been set. ### GetEnvVars -`func (o *CreateProjectConfigDTO) GetEnvVars() map[string]string` +`func (o *CreateWorkspaceTemplateDTO) GetEnvVars() map[string]string` GetEnvVars returns the EnvVars field if non-nil, zero value otherwise. ### GetEnvVarsOk -`func (o *CreateProjectConfigDTO) GetEnvVarsOk() (*map[string]string, bool)` +`func (o *CreateWorkspaceTemplateDTO) GetEnvVarsOk() (*map[string]string, bool)` GetEnvVarsOk returns a tuple with the EnvVars field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. ### SetEnvVars -`func (o *CreateProjectConfigDTO) SetEnvVars(v map[string]string)` +`func (o *CreateWorkspaceTemplateDTO) SetEnvVars(v map[string]string)` SetEnvVars sets EnvVars field to given value. ### GetGitProviderConfigId -`func (o *CreateProjectConfigDTO) GetGitProviderConfigId() string` +`func (o *CreateWorkspaceTemplateDTO) GetGitProviderConfigId() string` GetGitProviderConfigId returns the GitProviderConfigId field if non-nil, zero value otherwise. ### GetGitProviderConfigIdOk -`func (o *CreateProjectConfigDTO) GetGitProviderConfigIdOk() (*string, bool)` +`func (o *CreateWorkspaceTemplateDTO) GetGitProviderConfigIdOk() (*string, bool)` GetGitProviderConfigIdOk returns a tuple with the GitProviderConfigId field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. ### SetGitProviderConfigId -`func (o *CreateProjectConfigDTO) SetGitProviderConfigId(v string)` +`func (o *CreateWorkspaceTemplateDTO) SetGitProviderConfigId(v string)` SetGitProviderConfigId sets GitProviderConfigId field to given value. ### HasGitProviderConfigId -`func (o *CreateProjectConfigDTO) HasGitProviderConfigId() bool` +`func (o *CreateWorkspaceTemplateDTO) HasGitProviderConfigId() bool` HasGitProviderConfigId returns a boolean if a field has been set. ### GetImage -`func (o *CreateProjectConfigDTO) GetImage() string` +`func (o *CreateWorkspaceTemplateDTO) GetImage() string` GetImage returns the Image field if non-nil, zero value otherwise. ### GetImageOk -`func (o *CreateProjectConfigDTO) GetImageOk() (*string, bool)` +`func (o *CreateWorkspaceTemplateDTO) GetImageOk() (*string, bool)` GetImageOk returns a tuple with the Image field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. ### SetImage -`func (o *CreateProjectConfigDTO) SetImage(v string)` +`func (o *CreateWorkspaceTemplateDTO) SetImage(v string)` SetImage sets Image field to given value. ### HasImage -`func (o *CreateProjectConfigDTO) HasImage() bool` +`func (o *CreateWorkspaceTemplateDTO) HasImage() bool` HasImage returns a boolean if a field has been set. ### GetName -`func (o *CreateProjectConfigDTO) GetName() string` +`func (o *CreateWorkspaceTemplateDTO) GetName() string` GetName returns the Name field if non-nil, zero value otherwise. ### GetNameOk -`func (o *CreateProjectConfigDTO) GetNameOk() (*string, bool)` +`func (o *CreateWorkspaceTemplateDTO) GetNameOk() (*string, bool)` GetNameOk returns a tuple with the Name field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. ### SetName -`func (o *CreateProjectConfigDTO) SetName(v string)` +`func (o *CreateWorkspaceTemplateDTO) SetName(v string)` SetName sets Name field to given value. ### GetRepositoryUrl -`func (o *CreateProjectConfigDTO) GetRepositoryUrl() string` +`func (o *CreateWorkspaceTemplateDTO) GetRepositoryUrl() string` GetRepositoryUrl returns the RepositoryUrl field if non-nil, zero value otherwise. ### GetRepositoryUrlOk -`func (o *CreateProjectConfigDTO) GetRepositoryUrlOk() (*string, bool)` +`func (o *CreateWorkspaceTemplateDTO) GetRepositoryUrlOk() (*string, bool)` GetRepositoryUrlOk returns a tuple with the RepositoryUrl field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. ### SetRepositoryUrl -`func (o *CreateProjectConfigDTO) SetRepositoryUrl(v string)` +`func (o *CreateWorkspaceTemplateDTO) SetRepositoryUrl(v string)` SetRepositoryUrl sets RepositoryUrl field to given value. ### GetUser -`func (o *CreateProjectConfigDTO) GetUser() string` +`func (o *CreateWorkspaceTemplateDTO) GetUser() string` GetUser returns the User field if non-nil, zero value otherwise. ### GetUserOk -`func (o *CreateProjectConfigDTO) GetUserOk() (*string, bool)` +`func (o *CreateWorkspaceTemplateDTO) GetUserOk() (*string, bool)` GetUserOk returns a tuple with the User field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. ### SetUser -`func (o *CreateProjectConfigDTO) SetUser(v string)` +`func (o *CreateWorkspaceTemplateDTO) SetUser(v string)` SetUser sets User field to given value. ### HasUser -`func (o *CreateProjectConfigDTO) HasUser() bool` +`func (o *CreateWorkspaceTemplateDTO) HasUser() bool` HasUser returns a boolean if a field has been set. diff --git a/pkg/apiclient/docs/EnvVarAPI.md b/pkg/apiclient/docs/EnvVarAPI.md new file mode 100644 index 0000000000..e4520b1268 --- /dev/null +++ b/pkg/apiclient/docs/EnvVarAPI.md @@ -0,0 +1,204 @@ +# \EnvVarAPI + +All URIs are relative to *http://localhost:3986* + +Method | HTTP request | Description +------------- | ------------- | ------------- +[**DeleteEnvironmentVariable**](EnvVarAPI.md#DeleteEnvironmentVariable) | **Delete** /env/{key} | Delete environment variable +[**ListEnvironmentVariables**](EnvVarAPI.md#ListEnvironmentVariables) | **Get** /env | List environment variables +[**SaveEnvironmentVariable**](EnvVarAPI.md#SaveEnvironmentVariable) | **Put** /env | Save environment variable + + + +## DeleteEnvironmentVariable + +> DeleteEnvironmentVariable(ctx, key).Execute() + +Delete environment variable + + + +### Example + +```go +package main + +import ( + "context" + "fmt" + "os" + openapiclient "github.com/GIT_USER_ID/GIT_REPO_ID/apiclient" +) + +func main() { + key := "key_example" // string | Environment Variable Key + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + r, err := apiClient.EnvVarAPI.DeleteEnvironmentVariable(context.Background(), key).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `EnvVarAPI.DeleteEnvironmentVariable``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } +} +``` + +### Path Parameters + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- +**ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. +**key** | **string** | Environment Variable Key | + +### Other Parameters + +Other parameters are passed through a pointer to a apiDeleteEnvironmentVariableRequest struct via the builder pattern + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + + +### Return type + + (empty response body) + +### Authorization + +[Bearer](../README.md#Bearer) + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: Not defined + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) +[[Back to Model list]](../README.md#documentation-for-models) +[[Back to README]](../README.md) + + +## ListEnvironmentVariables + +> []EnvironmentVariable ListEnvironmentVariables(ctx).Execute() + +List environment variables + + + +### Example + +```go +package main + +import ( + "context" + "fmt" + "os" + openapiclient "github.com/GIT_USER_ID/GIT_REPO_ID/apiclient" +) + +func main() { + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.EnvVarAPI.ListEnvironmentVariables(context.Background()).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `EnvVarAPI.ListEnvironmentVariables``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `ListEnvironmentVariables`: []EnvironmentVariable + fmt.Fprintf(os.Stdout, "Response from `EnvVarAPI.ListEnvironmentVariables`: %v\n", resp) +} +``` + +### Path Parameters + +This endpoint does not need any parameter. + +### Other Parameters + +Other parameters are passed through a pointer to a apiListEnvironmentVariablesRequest struct via the builder pattern + + +### Return type + +[**[]EnvironmentVariable**](EnvironmentVariable.md) + +### Authorization + +[Bearer](../README.md#Bearer) + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) +[[Back to Model list]](../README.md#documentation-for-models) +[[Back to README]](../README.md) + + +## SaveEnvironmentVariable + +> SaveEnvironmentVariable(ctx).EnvironmentVariable(environmentVariable).Execute() + +Save environment variable + + + +### Example + +```go +package main + +import ( + "context" + "fmt" + "os" + openapiclient "github.com/GIT_USER_ID/GIT_REPO_ID/apiclient" +) + +func main() { + environmentVariable := *openapiclient.NewEnvironmentVariable("Key_example", "Value_example") // EnvironmentVariable | Environment Variable + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + r, err := apiClient.EnvVarAPI.SaveEnvironmentVariable(context.Background()).EnvironmentVariable(environmentVariable).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `EnvVarAPI.SaveEnvironmentVariable``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } +} +``` + +### Path Parameters + + + +### Other Parameters + +Other parameters are passed through a pointer to a apiSaveEnvironmentVariableRequest struct via the builder pattern + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **environmentVariable** | [**EnvironmentVariable**](EnvironmentVariable.md) | Environment Variable | + +### Return type + + (empty response body) + +### Authorization + +[Bearer](../README.md#Bearer) + +### HTTP request headers + +- **Content-Type**: application/json +- **Accept**: Not defined + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) +[[Back to Model list]](../README.md#documentation-for-models) +[[Back to README]](../README.md) + diff --git a/pkg/apiclient/docs/EnvironmentVariable.md b/pkg/apiclient/docs/EnvironmentVariable.md new file mode 100644 index 0000000000..5fa727d4f2 --- /dev/null +++ b/pkg/apiclient/docs/EnvironmentVariable.md @@ -0,0 +1,72 @@ +# EnvironmentVariable + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Key** | **string** | | +**Value** | **string** | | + +## Methods + +### NewEnvironmentVariable + +`func NewEnvironmentVariable(key string, value string, ) *EnvironmentVariable` + +NewEnvironmentVariable instantiates a new EnvironmentVariable object +This constructor will assign default values to properties that have it defined, +and makes sure properties required by API are set, but the set of arguments +will change when the set of required properties is changed + +### NewEnvironmentVariableWithDefaults + +`func NewEnvironmentVariableWithDefaults() *EnvironmentVariable` + +NewEnvironmentVariableWithDefaults instantiates a new EnvironmentVariable object +This constructor will only assign default values to properties that have it defined, +but it doesn't guarantee that properties required by API are set + +### GetKey + +`func (o *EnvironmentVariable) GetKey() string` + +GetKey returns the Key field if non-nil, zero value otherwise. + +### GetKeyOk + +`func (o *EnvironmentVariable) GetKeyOk() (*string, bool)` + +GetKeyOk returns a tuple with the Key field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetKey + +`func (o *EnvironmentVariable) SetKey(v string)` + +SetKey sets Key field to given value. + + +### GetValue + +`func (o *EnvironmentVariable) GetValue() string` + +GetValue returns the Value field if non-nil, zero value otherwise. + +### GetValueOk + +`func (o *EnvironmentVariable) GetValueOk() (*string, bool)` + +GetValueOk returns a tuple with the Value field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetValue + +`func (o *EnvironmentVariable) SetValue(v string)` + +SetValue sets Value field to given value. + + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/pkg/apiclient/docs/GitProviderAPI.md b/pkg/apiclient/docs/GitProviderAPI.md index 2fa81645cd..c6f72b1e05 100644 --- a/pkg/apiclient/docs/GitProviderAPI.md +++ b/pkg/apiclient/docs/GitProviderAPI.md @@ -4,9 +4,10 @@ All URIs are relative to *http://localhost:3986* Method | HTTP request | Description ------------- | ------------- | ------------- +[**DeleteGitProvider**](GitProviderAPI.md#DeleteGitProvider) | **Delete** /gitprovider/{gitProviderId} | Delete Git provider +[**FindGitProvider**](GitProviderAPI.md#FindGitProvider) | **Get** /gitprovider/{gitProviderId} | Find Git provider +[**FindGitProviderIdForUrl**](GitProviderAPI.md#FindGitProviderIdForUrl) | **Get** /gitprovider/id-for-url/{url} | Find Git provider ID [**GetGitContext**](GitProviderAPI.md#GetGitContext) | **Post** /gitprovider/context | Get Git context -[**GetGitProvider**](GitProviderAPI.md#GetGitProvider) | **Get** /gitprovider/{gitProviderId} | Get Git provider -[**GetGitProviderIdForUrl**](GitProviderAPI.md#GetGitProviderIdForUrl) | **Get** /gitprovider/id-for-url/{url} | Get Git provider ID [**GetGitUser**](GitProviderAPI.md#GetGitUser) | **Get** /gitprovider/{gitProviderId}/user | Get Git context [**GetNamespaces**](GitProviderAPI.md#GetNamespaces) | **Get** /gitprovider/{gitProviderId}/namespaces | Get Git namespaces [**GetRepoBranches**](GitProviderAPI.md#GetRepoBranches) | **Get** /gitprovider/{gitProviderId}/{namespaceId}/{repositoryId}/branches | Get Git repository branches @@ -15,16 +16,15 @@ Method | HTTP request | Description [**GetUrlFromRepository**](GitProviderAPI.md#GetUrlFromRepository) | **Post** /gitprovider/context/url | Get URL from Git repository [**ListGitProviders**](GitProviderAPI.md#ListGitProviders) | **Get** /gitprovider | List Git providers [**ListGitProvidersForUrl**](GitProviderAPI.md#ListGitProvidersForUrl) | **Get** /gitprovider/for-url/{url} | List Git providers for url -[**RemoveGitProvider**](GitProviderAPI.md#RemoveGitProvider) | **Delete** /gitprovider/{gitProviderId} | Remove Git provider -[**SetGitProvider**](GitProviderAPI.md#SetGitProvider) | **Put** /gitprovider | Set Git provider +[**SaveGitProvider**](GitProviderAPI.md#SaveGitProvider) | **Put** /gitprovider | Save Git provider -## GetGitContext +## DeleteGitProvider -> GitRepository GetGitContext(ctx).Repository(repository).Execute() +> DeleteGitProvider(ctx, gitProviderId).Execute() -Get Git context +Delete Git provider @@ -41,36 +41,38 @@ import ( ) func main() { - repository := *openapiclient.NewGetRepositoryContext("Url_example") // GetRepositoryContext | Get repository context + gitProviderId := "gitProviderId_example" // string | Git provider configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.GitProviderAPI.GetGitContext(context.Background()).Repository(repository).Execute() + r, err := apiClient.GitProviderAPI.DeleteGitProvider(context.Background(), gitProviderId).Execute() if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `GitProviderAPI.GetGitContext``: %v\n", err) + fmt.Fprintf(os.Stderr, "Error when calling `GitProviderAPI.DeleteGitProvider``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) } - // response from `GetGitContext`: GitRepository - fmt.Fprintf(os.Stdout, "Response from `GitProviderAPI.GetGitContext`: %v\n", resp) } ``` ### Path Parameters +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- +**ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. +**gitProviderId** | **string** | Git provider | ### Other Parameters -Other parameters are passed through a pointer to a apiGetGitContextRequest struct via the builder pattern +Other parameters are passed through a pointer to a apiDeleteGitProviderRequest struct via the builder pattern Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - **repository** | [**GetRepositoryContext**](GetRepositoryContext.md) | Get repository context | + ### Return type -[**GitRepository**](GitRepository.md) + (empty response body) ### Authorization @@ -79,18 +81,18 @@ Name | Type | Description | Notes ### HTTP request headers - **Content-Type**: Not defined -- **Accept**: application/json +- **Accept**: Not defined [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) -## GetGitProvider +## FindGitProvider -> GitProvider GetGitProvider(ctx, gitProviderId).Execute() +> GitProvider FindGitProvider(ctx, gitProviderId).Execute() -Get Git provider +Find Git provider @@ -111,13 +113,13 @@ func main() { configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.GitProviderAPI.GetGitProvider(context.Background(), gitProviderId).Execute() + resp, r, err := apiClient.GitProviderAPI.FindGitProvider(context.Background(), gitProviderId).Execute() if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `GitProviderAPI.GetGitProvider``: %v\n", err) + fmt.Fprintf(os.Stderr, "Error when calling `GitProviderAPI.FindGitProvider``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) } - // response from `GetGitProvider`: GitProvider - fmt.Fprintf(os.Stdout, "Response from `GitProviderAPI.GetGitProvider`: %v\n", resp) + // response from `FindGitProvider`: GitProvider + fmt.Fprintf(os.Stdout, "Response from `GitProviderAPI.FindGitProvider`: %v\n", resp) } ``` @@ -131,7 +133,7 @@ Name | Type | Description | Notes ### Other Parameters -Other parameters are passed through a pointer to a apiGetGitProviderRequest struct via the builder pattern +Other parameters are passed through a pointer to a apiFindGitProviderRequest struct via the builder pattern Name | Type | Description | Notes @@ -156,11 +158,11 @@ Name | Type | Description | Notes [[Back to README]](../README.md) -## GetGitProviderIdForUrl +## FindGitProviderIdForUrl -> string GetGitProviderIdForUrl(ctx, url).Execute() +> string FindGitProviderIdForUrl(ctx, url).Execute() -Get Git provider ID +Find Git provider ID @@ -181,13 +183,13 @@ func main() { configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.GitProviderAPI.GetGitProviderIdForUrl(context.Background(), url).Execute() + resp, r, err := apiClient.GitProviderAPI.FindGitProviderIdForUrl(context.Background(), url).Execute() if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `GitProviderAPI.GetGitProviderIdForUrl``: %v\n", err) + fmt.Fprintf(os.Stderr, "Error when calling `GitProviderAPI.FindGitProviderIdForUrl``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) } - // response from `GetGitProviderIdForUrl`: string - fmt.Fprintf(os.Stdout, "Response from `GitProviderAPI.GetGitProviderIdForUrl`: %v\n", resp) + // response from `FindGitProviderIdForUrl`: string + fmt.Fprintf(os.Stdout, "Response from `GitProviderAPI.FindGitProviderIdForUrl`: %v\n", resp) } ``` @@ -201,7 +203,7 @@ Name | Type | Description | Notes ### Other Parameters -Other parameters are passed through a pointer to a apiGetGitProviderIdForUrlRequest struct via the builder pattern +Other parameters are passed through a pointer to a apiFindGitProviderIdForUrlRequest struct via the builder pattern Name | Type | Description | Notes @@ -226,6 +228,72 @@ Name | Type | Description | Notes [[Back to README]](../README.md) +## GetGitContext + +> GitRepository GetGitContext(ctx).Repository(repository).Execute() + +Get Git context + + + +### Example + +```go +package main + +import ( + "context" + "fmt" + "os" + openapiclient "github.com/GIT_USER_ID/GIT_REPO_ID/apiclient" +) + +func main() { + repository := *openapiclient.NewGetRepositoryContext("Url_example") // GetRepositoryContext | Get repository context + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.GitProviderAPI.GetGitContext(context.Background()).Repository(repository).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `GitProviderAPI.GetGitContext``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `GetGitContext`: GitRepository + fmt.Fprintf(os.Stdout, "Response from `GitProviderAPI.GetGitContext`: %v\n", resp) +} +``` + +### Path Parameters + + + +### Other Parameters + +Other parameters are passed through a pointer to a apiGetGitContextRequest struct via the builder pattern + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **repository** | [**GetRepositoryContext**](GetRepositoryContext.md) | Get repository context | + +### Return type + +[**GitRepository**](GitRepository.md) + +### Authorization + +[Bearer](../README.md#Bearer) + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) +[[Back to Model list]](../README.md#documentation-for-models) +[[Back to README]](../README.md) + + ## GetGitUser > GitUser GetGitUser(ctx, gitProviderId).Execute() @@ -804,79 +872,11 @@ Name | Type | Description | Notes [[Back to README]](../README.md) -## RemoveGitProvider - -> RemoveGitProvider(ctx, gitProviderId).Execute() - -Remove Git provider - - - -### Example - -```go -package main - -import ( - "context" - "fmt" - "os" - openapiclient "github.com/GIT_USER_ID/GIT_REPO_ID/apiclient" -) - -func main() { - gitProviderId := "gitProviderId_example" // string | Git provider - - configuration := openapiclient.NewConfiguration() - apiClient := openapiclient.NewAPIClient(configuration) - r, err := apiClient.GitProviderAPI.RemoveGitProvider(context.Background(), gitProviderId).Execute() - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `GitProviderAPI.RemoveGitProvider``: %v\n", err) - fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - } -} -``` - -### Path Parameters - - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- -**ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. -**gitProviderId** | **string** | Git provider | - -### Other Parameters - -Other parameters are passed through a pointer to a apiRemoveGitProviderRequest struct via the builder pattern - - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - - -### Return type - - (empty response body) - -### Authorization - -[Bearer](../README.md#Bearer) - -### HTTP request headers - -- **Content-Type**: Not defined -- **Accept**: Not defined - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) -[[Back to Model list]](../README.md#documentation-for-models) -[[Back to README]](../README.md) - - -## SetGitProvider +## SaveGitProvider -> SetGitProvider(ctx).GitProviderConfig(gitProviderConfig).Execute() +> SaveGitProvider(ctx).GitProviderConfig(gitProviderConfig).Execute() -Set Git provider +Save Git provider @@ -897,9 +897,9 @@ func main() { configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - r, err := apiClient.GitProviderAPI.SetGitProvider(context.Background()).GitProviderConfig(gitProviderConfig).Execute() + r, err := apiClient.GitProviderAPI.SaveGitProvider(context.Background()).GitProviderConfig(gitProviderConfig).Execute() if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `GitProviderAPI.SetGitProvider``: %v\n", err) + fmt.Fprintf(os.Stderr, "Error when calling `GitProviderAPI.SaveGitProvider``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) } } @@ -911,7 +911,7 @@ func main() { ### Other Parameters -Other parameters are passed through a pointer to a apiSetGitProviderRequest struct via the builder pattern +Other parameters are passed through a pointer to a apiSaveGitProviderRequest struct via the builder pattern Name | Type | Description | Notes diff --git a/pkg/apiclient/docs/InstallProviderRequest.md b/pkg/apiclient/docs/InstallProviderRequest.md deleted file mode 100644 index 4e1677ed24..0000000000 --- a/pkg/apiclient/docs/InstallProviderRequest.md +++ /dev/null @@ -1,72 +0,0 @@ -# InstallProviderRequest - -## Properties - -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**DownloadUrls** | **map[string]string** | | -**Name** | **string** | | - -## Methods - -### NewInstallProviderRequest - -`func NewInstallProviderRequest(downloadUrls map[string]string, name string, ) *InstallProviderRequest` - -NewInstallProviderRequest instantiates a new InstallProviderRequest object -This constructor will assign default values to properties that have it defined, -and makes sure properties required by API are set, but the set of arguments -will change when the set of required properties is changed - -### NewInstallProviderRequestWithDefaults - -`func NewInstallProviderRequestWithDefaults() *InstallProviderRequest` - -NewInstallProviderRequestWithDefaults instantiates a new InstallProviderRequest object -This constructor will only assign default values to properties that have it defined, -but it doesn't guarantee that properties required by API are set - -### GetDownloadUrls - -`func (o *InstallProviderRequest) GetDownloadUrls() map[string]string` - -GetDownloadUrls returns the DownloadUrls field if non-nil, zero value otherwise. - -### GetDownloadUrlsOk - -`func (o *InstallProviderRequest) GetDownloadUrlsOk() (*map[string]string, bool)` - -GetDownloadUrlsOk returns a tuple with the DownloadUrls field if it's non-nil, zero value otherwise -and a boolean to check if the value has been set. - -### SetDownloadUrls - -`func (o *InstallProviderRequest) SetDownloadUrls(v map[string]string)` - -SetDownloadUrls sets DownloadUrls field to given value. - - -### GetName - -`func (o *InstallProviderRequest) GetName() string` - -GetName returns the Name field if non-nil, zero value otherwise. - -### GetNameOk - -`func (o *InstallProviderRequest) GetNameOk() (*string, bool)` - -GetNameOk returns a tuple with the Name field if it's non-nil, zero value otherwise -and a boolean to check if the value has been set. - -### SetName - -`func (o *InstallProviderRequest) SetName(v string)` - -SetName sets Name field to given value. - - - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/pkg/apiclient/docs/Job.md b/pkg/apiclient/docs/Job.md new file mode 100644 index 0000000000..3b28ec77ea --- /dev/null +++ b/pkg/apiclient/docs/Job.md @@ -0,0 +1,255 @@ +# Job + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Action** | [**ModelsJobAction**](ModelsJobAction.md) | | +**CreatedAt** | **string** | | +**Error** | Pointer to **string** | | [optional] +**Id** | **string** | | +**Metadata** | Pointer to **string** | JSON encoded metadata | [optional] +**ResourceId** | **string** | | +**ResourceType** | [**ResourceType**](ResourceType.md) | | +**RunnerId** | Pointer to **string** | | [optional] +**State** | [**JobState**](JobState.md) | | +**UpdatedAt** | **string** | | + +## Methods + +### NewJob + +`func NewJob(action ModelsJobAction, createdAt string, id string, resourceId string, resourceType ResourceType, state JobState, updatedAt string, ) *Job` + +NewJob instantiates a new Job object +This constructor will assign default values to properties that have it defined, +and makes sure properties required by API are set, but the set of arguments +will change when the set of required properties is changed + +### NewJobWithDefaults + +`func NewJobWithDefaults() *Job` + +NewJobWithDefaults instantiates a new Job object +This constructor will only assign default values to properties that have it defined, +but it doesn't guarantee that properties required by API are set + +### GetAction + +`func (o *Job) GetAction() ModelsJobAction` + +GetAction returns the Action field if non-nil, zero value otherwise. + +### GetActionOk + +`func (o *Job) GetActionOk() (*ModelsJobAction, bool)` + +GetActionOk returns a tuple with the Action field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetAction + +`func (o *Job) SetAction(v ModelsJobAction)` + +SetAction sets Action field to given value. + + +### GetCreatedAt + +`func (o *Job) GetCreatedAt() string` + +GetCreatedAt returns the CreatedAt field if non-nil, zero value otherwise. + +### GetCreatedAtOk + +`func (o *Job) GetCreatedAtOk() (*string, bool)` + +GetCreatedAtOk returns a tuple with the CreatedAt field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetCreatedAt + +`func (o *Job) SetCreatedAt(v string)` + +SetCreatedAt sets CreatedAt field to given value. + + +### GetError + +`func (o *Job) GetError() string` + +GetError returns the Error field if non-nil, zero value otherwise. + +### GetErrorOk + +`func (o *Job) GetErrorOk() (*string, bool)` + +GetErrorOk returns a tuple with the Error field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetError + +`func (o *Job) SetError(v string)` + +SetError sets Error field to given value. + +### HasError + +`func (o *Job) HasError() bool` + +HasError returns a boolean if a field has been set. + +### GetId + +`func (o *Job) GetId() string` + +GetId returns the Id field if non-nil, zero value otherwise. + +### GetIdOk + +`func (o *Job) GetIdOk() (*string, bool)` + +GetIdOk returns a tuple with the Id field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetId + +`func (o *Job) SetId(v string)` + +SetId sets Id field to given value. + + +### GetMetadata + +`func (o *Job) GetMetadata() string` + +GetMetadata returns the Metadata field if non-nil, zero value otherwise. + +### GetMetadataOk + +`func (o *Job) GetMetadataOk() (*string, bool)` + +GetMetadataOk returns a tuple with the Metadata field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetMetadata + +`func (o *Job) SetMetadata(v string)` + +SetMetadata sets Metadata field to given value. + +### HasMetadata + +`func (o *Job) HasMetadata() bool` + +HasMetadata returns a boolean if a field has been set. + +### GetResourceId + +`func (o *Job) GetResourceId() string` + +GetResourceId returns the ResourceId field if non-nil, zero value otherwise. + +### GetResourceIdOk + +`func (o *Job) GetResourceIdOk() (*string, bool)` + +GetResourceIdOk returns a tuple with the ResourceId field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetResourceId + +`func (o *Job) SetResourceId(v string)` + +SetResourceId sets ResourceId field to given value. + + +### GetResourceType + +`func (o *Job) GetResourceType() ResourceType` + +GetResourceType returns the ResourceType field if non-nil, zero value otherwise. + +### GetResourceTypeOk + +`func (o *Job) GetResourceTypeOk() (*ResourceType, bool)` + +GetResourceTypeOk returns a tuple with the ResourceType field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetResourceType + +`func (o *Job) SetResourceType(v ResourceType)` + +SetResourceType sets ResourceType field to given value. + + +### GetRunnerId + +`func (o *Job) GetRunnerId() string` + +GetRunnerId returns the RunnerId field if non-nil, zero value otherwise. + +### GetRunnerIdOk + +`func (o *Job) GetRunnerIdOk() (*string, bool)` + +GetRunnerIdOk returns a tuple with the RunnerId field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetRunnerId + +`func (o *Job) SetRunnerId(v string)` + +SetRunnerId sets RunnerId field to given value. + +### HasRunnerId + +`func (o *Job) HasRunnerId() bool` + +HasRunnerId returns a boolean if a field has been set. + +### GetState + +`func (o *Job) GetState() JobState` + +GetState returns the State field if non-nil, zero value otherwise. + +### GetStateOk + +`func (o *Job) GetStateOk() (*JobState, bool)` + +GetStateOk returns a tuple with the State field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetState + +`func (o *Job) SetState(v JobState)` + +SetState sets State field to given value. + + +### GetUpdatedAt + +`func (o *Job) GetUpdatedAt() string` + +GetUpdatedAt returns the UpdatedAt field if non-nil, zero value otherwise. + +### GetUpdatedAtOk + +`func (o *Job) GetUpdatedAtOk() (*string, bool)` + +GetUpdatedAtOk returns a tuple with the UpdatedAt field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetUpdatedAt + +`func (o *Job) SetUpdatedAt(v string)` + +SetUpdatedAt sets UpdatedAt field to given value. + + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/pkg/apiclient/docs/JobAPI.md b/pkg/apiclient/docs/JobAPI.md new file mode 100644 index 0000000000..198bafb941 --- /dev/null +++ b/pkg/apiclient/docs/JobAPI.md @@ -0,0 +1,81 @@ +# \JobAPI + +All URIs are relative to *http://localhost:3986* + +Method | HTTP request | Description +------------- | ------------- | ------------- +[**ListJobs**](JobAPI.md#ListJobs) | **Get** /job | List jobs + + + +## ListJobs + +> []Job ListJobs(ctx).States(states).Actions(actions).ResourceId(resourceId).ResourceType(resourceType).Execute() + +List jobs + + + +### Example + +```go +package main + +import ( + "context" + "fmt" + "os" + openapiclient "github.com/GIT_USER_ID/GIT_REPO_ID/apiclient" +) + +func main() { + states := []string{"Inner_example"} // []string | Job States (optional) + actions := []string{"Inner_example"} // []string | Job Actions (optional) + resourceId := "resourceId_example" // string | Resource ID (optional) + resourceType := "resourceType_example" // string | Resource Type (optional) + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.JobAPI.ListJobs(context.Background()).States(states).Actions(actions).ResourceId(resourceId).ResourceType(resourceType).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `JobAPI.ListJobs``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `ListJobs`: []Job + fmt.Fprintf(os.Stdout, "Response from `JobAPI.ListJobs`: %v\n", resp) +} +``` + +### Path Parameters + + + +### Other Parameters + +Other parameters are passed through a pointer to a apiListJobsRequest struct via the builder pattern + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **states** | **[]string** | Job States | + **actions** | **[]string** | Job Actions | + **resourceId** | **string** | Resource ID | + **resourceType** | **string** | Resource Type | + +### Return type + +[**[]Job**](Job.md) + +### Authorization + +[Bearer](../README.md#Bearer) + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) +[[Back to Model list]](../README.md#documentation-for-models) +[[Back to README]](../README.md) + diff --git a/pkg/apiclient/docs/JobState.md b/pkg/apiclient/docs/JobState.md new file mode 100644 index 0000000000..3d2915aea3 --- /dev/null +++ b/pkg/apiclient/docs/JobState.md @@ -0,0 +1,17 @@ +# JobState + +## Enum + + +* `JobStatePending` (value: `"pending"`) + +* `JobStateRunning` (value: `"running"`) + +* `JobStateError` (value: `"error"`) + +* `JobStateSuccess` (value: `"success"`) + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/pkg/apiclient/docs/ApikeyApiKeyType.md b/pkg/apiclient/docs/ModelsApiKeyType.md similarity index 72% rename from pkg/apiclient/docs/ApikeyApiKeyType.md rename to pkg/apiclient/docs/ModelsApiKeyType.md index 7977b92f28..370b7fd53d 100644 --- a/pkg/apiclient/docs/ApikeyApiKeyType.md +++ b/pkg/apiclient/docs/ModelsApiKeyType.md @@ -1,14 +1,16 @@ -# ApikeyApiKeyType +# ModelsApiKeyType ## Enum * `ApiKeyTypeClient` (value: `"client"`) -* `ApiKeyTypeProject` (value: `"project"`) - * `ApiKeyTypeWorkspace` (value: `"workspace"`) +* `ApiKeyTypeTarget` (value: `"target"`) + +* `ApiKeyTypeRunner` (value: `"runner"`) + [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pkg/apiclient/docs/ModelsJobAction.md b/pkg/apiclient/docs/ModelsJobAction.md new file mode 100644 index 0000000000..d05b3c15af --- /dev/null +++ b/pkg/apiclient/docs/ModelsJobAction.md @@ -0,0 +1,29 @@ +# ModelsJobAction + +## Enum + + +* `JobActionCreate` (value: `"create"`) + +* `JobActionStart` (value: `"start"`) + +* `JobActionStop` (value: `"stop"`) + +* `JobActionRestart` (value: `"restart"`) + +* `JobActionDelete` (value: `"delete"`) + +* `JobActionForceDelete` (value: `"force-delete"`) + +* `JobActionRun` (value: `"run"`) + +* `JobActionInstallProvider` (value: `"install-provider"`) + +* `JobActionUninstallProvider` (value: `"uninstall-provider"`) + +* `JobActionUpdateProvider` (value: `"update-provider"`) + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/pkg/apiclient/docs/ModelsResourceStateName.md b/pkg/apiclient/docs/ModelsResourceStateName.md new file mode 100644 index 0000000000..1b06ed61cb --- /dev/null +++ b/pkg/apiclient/docs/ModelsResourceStateName.md @@ -0,0 +1,47 @@ +# ModelsResourceStateName + +## Enum + + +* `ResourceStateNameUndefined` (value: `"undefined"`) + +* `ResourceStateNamePendingRun` (value: `"pending-run"`) + +* `ResourceStateNameRunning` (value: `"running"`) + +* `ResourceStateNameRunSuccessful` (value: `"run-successful"`) + +* `ResourceStateNamePendingCreate` (value: `"pending-create"`) + +* `ResourceStateNameCreating` (value: `"creating"`) + +* `ResourceStateNamePendingStart` (value: `"pending-start"`) + +* `ResourceStateNameStarting` (value: `"starting"`) + +* `ResourceStateNameStarted` (value: `"started"`) + +* `ResourceStateNamePendingStop` (value: `"pending-stop"`) + +* `ResourceStateNameStopping` (value: `"stopping"`) + +* `ResourceStateNameStopped` (value: `"stopped"`) + +* `ResourceStateNamePendingRestart` (value: `"pending-restart"`) + +* `ResourceStateNameError` (value: `"error"`) + +* `ResourceStateNameUnresponsive` (value: `"unresponsive"`) + +* `ResourceStateNamePendingDelete` (value: `"pending-delete"`) + +* `ResourceStateNamePendingForcedDelete` (value: `"pending-forced-delete"`) + +* `ResourceStateNameDeleting` (value: `"deleting"`) + +* `ResourceStateNameDeleted` (value: `"deleted"`) + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/pkg/apiclient/docs/ModelsTargetConfigPropertyType.md b/pkg/apiclient/docs/ModelsTargetConfigPropertyType.md new file mode 100644 index 0000000000..233b8411db --- /dev/null +++ b/pkg/apiclient/docs/ModelsTargetConfigPropertyType.md @@ -0,0 +1,21 @@ +# ModelsTargetConfigPropertyType + +## Enum + + +* `TargetConfigPropertyTypeString` (value: `"string"`) + +* `TargetConfigPropertyTypeOption` (value: `"option"`) + +* `TargetConfigPropertyTypeBoolean` (value: `"boolean"`) + +* `TargetConfigPropertyTypeInt` (value: `"int"`) + +* `TargetConfigPropertyTypeFloat` (value: `"float"`) + +* `TargetConfigPropertyTypeFilePath` (value: `"file-path"`) + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/pkg/apiclient/docs/PrebuildAPI.md b/pkg/apiclient/docs/PrebuildAPI.md index a1dc453e86..60d47b918b 100644 --- a/pkg/apiclient/docs/PrebuildAPI.md +++ b/pkg/apiclient/docs/PrebuildAPI.md @@ -4,18 +4,18 @@ All URIs are relative to *http://localhost:3986* Method | HTTP request | Description ------------- | ------------- | ------------- -[**DeletePrebuild**](PrebuildAPI.md#DeletePrebuild) | **Delete** /project-config/{configName}/prebuild/{prebuildId} | Delete prebuild -[**GetPrebuild**](PrebuildAPI.md#GetPrebuild) | **Get** /project-config/{configName}/prebuild/{prebuildId} | Get prebuild -[**ListPrebuilds**](PrebuildAPI.md#ListPrebuilds) | **Get** /project-config/prebuild | List prebuilds -[**ListPrebuildsForProjectConfig**](PrebuildAPI.md#ListPrebuildsForProjectConfig) | **Get** /project-config/{configName}/prebuild | List prebuilds for project config -[**ProcessGitEvent**](PrebuildAPI.md#ProcessGitEvent) | **Post** /project-config/prebuild/process-git-event | ProcessGitEvent -[**SetPrebuild**](PrebuildAPI.md#SetPrebuild) | **Put** /project-config/{configName}/prebuild | Set prebuild +[**DeletePrebuild**](PrebuildAPI.md#DeletePrebuild) | **Delete** /workspace-template/{templateName}/prebuild/{prebuildId} | Delete prebuild +[**FindPrebuild**](PrebuildAPI.md#FindPrebuild) | **Get** /workspace-template/{templateName}/prebuild/{prebuildId} | Find prebuild +[**ListPrebuilds**](PrebuildAPI.md#ListPrebuilds) | **Get** /workspace-template/prebuild | List prebuilds +[**ListPrebuildsForWorkspaceTemplate**](PrebuildAPI.md#ListPrebuildsForWorkspaceTemplate) | **Get** /workspace-template/{templateName}/prebuild | List prebuilds for workspace template +[**ProcessGitEvent**](PrebuildAPI.md#ProcessGitEvent) | **Post** /workspace-template/prebuild/process-git-event | ProcessGitEvent +[**SavePrebuild**](PrebuildAPI.md#SavePrebuild) | **Put** /workspace-template/{templateName}/prebuild | Save prebuild ## DeletePrebuild -> DeletePrebuild(ctx, configName, prebuildId).Force(force).Execute() +> DeletePrebuild(ctx, templateName, prebuildId).Force(force).Execute() Delete prebuild @@ -34,13 +34,13 @@ import ( ) func main() { - configName := "configName_example" // string | Project config name + templateName := "templateName_example" // string | Workspace template name prebuildId := "prebuildId_example" // string | Prebuild ID force := true // bool | Force (optional) configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - r, err := apiClient.PrebuildAPI.DeletePrebuild(context.Background(), configName, prebuildId).Force(force).Execute() + r, err := apiClient.PrebuildAPI.DeletePrebuild(context.Background(), templateName, prebuildId).Force(force).Execute() if err != nil { fmt.Fprintf(os.Stderr, "Error when calling `PrebuildAPI.DeletePrebuild``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) @@ -54,7 +54,7 @@ func main() { Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. -**configName** | **string** | Project config name | +**templateName** | **string** | Workspace template name | **prebuildId** | **string** | Prebuild ID | ### Other Parameters @@ -86,11 +86,11 @@ Name | Type | Description | Notes [[Back to README]](../README.md) -## GetPrebuild +## FindPrebuild -> PrebuildDTO GetPrebuild(ctx, configName, prebuildId).Execute() +> PrebuildDTO FindPrebuild(ctx, templateName, prebuildId).Execute() -Get prebuild +Find prebuild @@ -107,18 +107,18 @@ import ( ) func main() { - configName := "configName_example" // string | Project config name + templateName := "templateName_example" // string | Workspace template name prebuildId := "prebuildId_example" // string | Prebuild ID configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.PrebuildAPI.GetPrebuild(context.Background(), configName, prebuildId).Execute() + resp, r, err := apiClient.PrebuildAPI.FindPrebuild(context.Background(), templateName, prebuildId).Execute() if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `PrebuildAPI.GetPrebuild``: %v\n", err) + fmt.Fprintf(os.Stderr, "Error when calling `PrebuildAPI.FindPrebuild``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) } - // response from `GetPrebuild`: PrebuildDTO - fmt.Fprintf(os.Stdout, "Response from `PrebuildAPI.GetPrebuild`: %v\n", resp) + // response from `FindPrebuild`: PrebuildDTO + fmt.Fprintf(os.Stdout, "Response from `PrebuildAPI.FindPrebuild`: %v\n", resp) } ``` @@ -128,12 +128,12 @@ func main() { Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. -**configName** | **string** | Project config name | +**templateName** | **string** | Workspace template name | **prebuildId** | **string** | Prebuild ID | ### Other Parameters -Other parameters are passed through a pointer to a apiGetPrebuildRequest struct via the builder pattern +Other parameters are passed through a pointer to a apiFindPrebuildRequest struct via the builder pattern Name | Type | Description | Notes @@ -220,11 +220,11 @@ Other parameters are passed through a pointer to a apiListPrebuildsRequest struc [[Back to README]](../README.md) -## ListPrebuildsForProjectConfig +## ListPrebuildsForWorkspaceTemplate -> []PrebuildDTO ListPrebuildsForProjectConfig(ctx, configName).Execute() +> []PrebuildDTO ListPrebuildsForWorkspaceTemplate(ctx, templateName).Execute() -List prebuilds for project config +List prebuilds for workspace template @@ -241,17 +241,17 @@ import ( ) func main() { - configName := "configName_example" // string | Config name + templateName := "templateName_example" // string | Template name configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.PrebuildAPI.ListPrebuildsForProjectConfig(context.Background(), configName).Execute() + resp, r, err := apiClient.PrebuildAPI.ListPrebuildsForWorkspaceTemplate(context.Background(), templateName).Execute() if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `PrebuildAPI.ListPrebuildsForProjectConfig``: %v\n", err) + fmt.Fprintf(os.Stderr, "Error when calling `PrebuildAPI.ListPrebuildsForWorkspaceTemplate``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) } - // response from `ListPrebuildsForProjectConfig`: []PrebuildDTO - fmt.Fprintf(os.Stdout, "Response from `PrebuildAPI.ListPrebuildsForProjectConfig`: %v\n", resp) + // response from `ListPrebuildsForWorkspaceTemplate`: []PrebuildDTO + fmt.Fprintf(os.Stdout, "Response from `PrebuildAPI.ListPrebuildsForWorkspaceTemplate`: %v\n", resp) } ``` @@ -261,11 +261,11 @@ func main() { Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. -**configName** | **string** | Config name | +**templateName** | **string** | Template name | ### Other Parameters -Other parameters are passed through a pointer to a apiListPrebuildsForProjectConfigRequest struct via the builder pattern +Other parameters are passed through a pointer to a apiListPrebuildsForWorkspaceTemplateRequest struct via the builder pattern Name | Type | Description | Notes @@ -292,7 +292,7 @@ Name | Type | Description | Notes ## ProcessGitEvent -> ProcessGitEvent(ctx).Workspace(workspace).Execute() +> ProcessGitEvent(ctx).Body(body).Execute() ProcessGitEvent @@ -311,11 +311,11 @@ import ( ) func main() { - workspace := map[string]interface{}{ ... } // map[string]interface{} | Webhook event + body := map[string]interface{}{ ... } // map[string]interface{} | Webhook event configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - r, err := apiClient.PrebuildAPI.ProcessGitEvent(context.Background()).Workspace(workspace).Execute() + r, err := apiClient.PrebuildAPI.ProcessGitEvent(context.Background()).Body(body).Execute() if err != nil { fmt.Fprintf(os.Stderr, "Error when calling `PrebuildAPI.ProcessGitEvent``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) @@ -334,7 +334,7 @@ Other parameters are passed through a pointer to a apiProcessGitEventRequest str Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - **workspace** | **map[string]interface{}** | Webhook event | + **body** | **map[string]interface{}** | Webhook event | ### Return type @@ -354,11 +354,11 @@ Name | Type | Description | Notes [[Back to README]](../README.md) -## SetPrebuild +## SavePrebuild -> string SetPrebuild(ctx, configName).Prebuild(prebuild).Execute() +> string SavePrebuild(ctx, templateName).Prebuild(prebuild).Execute() -Set prebuild +Save prebuild @@ -375,18 +375,18 @@ import ( ) func main() { - configName := "configName_example" // string | Config name + templateName := "templateName_example" // string | Template name prebuild := *openapiclient.NewCreatePrebuildDTO(int32(123)) // CreatePrebuildDTO | Prebuild configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.PrebuildAPI.SetPrebuild(context.Background(), configName).Prebuild(prebuild).Execute() + resp, r, err := apiClient.PrebuildAPI.SavePrebuild(context.Background(), templateName).Prebuild(prebuild).Execute() if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `PrebuildAPI.SetPrebuild``: %v\n", err) + fmt.Fprintf(os.Stderr, "Error when calling `PrebuildAPI.SavePrebuild``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) } - // response from `SetPrebuild`: string - fmt.Fprintf(os.Stdout, "Response from `PrebuildAPI.SetPrebuild`: %v\n", resp) + // response from `SavePrebuild`: string + fmt.Fprintf(os.Stdout, "Response from `PrebuildAPI.SavePrebuild`: %v\n", resp) } ``` @@ -396,11 +396,11 @@ func main() { Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. -**configName** | **string** | Config name | +**templateName** | **string** | Template name | ### Other Parameters -Other parameters are passed through a pointer to a apiSetPrebuildRequest struct via the builder pattern +Other parameters are passed through a pointer to a apiSavePrebuildRequest struct via the builder pattern Name | Type | Description | Notes diff --git a/pkg/apiclient/docs/PrebuildConfig.md b/pkg/apiclient/docs/PrebuildConfig.md index 9a03b4b8c6..ab084ebe17 100644 --- a/pkg/apiclient/docs/PrebuildConfig.md +++ b/pkg/apiclient/docs/PrebuildConfig.md @@ -5,7 +5,7 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- **Branch** | **string** | | -**CommitInterval** | **int32** | | +**CommitInterval** | Pointer to **int32** | | [optional] **Id** | **string** | | **Retention** | **int32** | | **TriggerFiles** | **[]string** | | @@ -14,7 +14,7 @@ Name | Type | Description | Notes ### NewPrebuildConfig -`func NewPrebuildConfig(branch string, commitInterval int32, id string, retention int32, triggerFiles []string, ) *PrebuildConfig` +`func NewPrebuildConfig(branch string, id string, retention int32, triggerFiles []string, ) *PrebuildConfig` NewPrebuildConfig instantiates a new PrebuildConfig object This constructor will assign default values to properties that have it defined, @@ -68,6 +68,11 @@ and a boolean to check if the value has been set. SetCommitInterval sets CommitInterval field to given value. +### HasCommitInterval + +`func (o *PrebuildConfig) HasCommitInterval() bool` + +HasCommitInterval returns a boolean if a field has been set. ### GetId diff --git a/pkg/apiclient/docs/PrebuildDTO.md b/pkg/apiclient/docs/PrebuildDTO.md index edae1929af..47e79879c2 100644 --- a/pkg/apiclient/docs/PrebuildDTO.md +++ b/pkg/apiclient/docs/PrebuildDTO.md @@ -7,15 +7,15 @@ Name | Type | Description | Notes **Branch** | **string** | | **CommitInterval** | Pointer to **int32** | | [optional] **Id** | **string** | | -**ProjectConfigName** | **string** | | **Retention** | **int32** | | **TriggerFiles** | Pointer to **[]string** | | [optional] +**WorkspaceTemplateName** | **string** | | ## Methods ### NewPrebuildDTO -`func NewPrebuildDTO(branch string, id string, projectConfigName string, retention int32, ) *PrebuildDTO` +`func NewPrebuildDTO(branch string, id string, retention int32, workspaceTemplateName string, ) *PrebuildDTO` NewPrebuildDTO instantiates a new PrebuildDTO object This constructor will assign default values to properties that have it defined, @@ -95,26 +95,6 @@ and a boolean to check if the value has been set. SetId sets Id field to given value. -### GetProjectConfigName - -`func (o *PrebuildDTO) GetProjectConfigName() string` - -GetProjectConfigName returns the ProjectConfigName field if non-nil, zero value otherwise. - -### GetProjectConfigNameOk - -`func (o *PrebuildDTO) GetProjectConfigNameOk() (*string, bool)` - -GetProjectConfigNameOk returns a tuple with the ProjectConfigName field if it's non-nil, zero value otherwise -and a boolean to check if the value has been set. - -### SetProjectConfigName - -`func (o *PrebuildDTO) SetProjectConfigName(v string)` - -SetProjectConfigName sets ProjectConfigName field to given value. - - ### GetRetention `func (o *PrebuildDTO) GetRetention() int32` @@ -160,6 +140,26 @@ SetTriggerFiles sets TriggerFiles field to given value. HasTriggerFiles returns a boolean if a field has been set. +### GetWorkspaceTemplateName + +`func (o *PrebuildDTO) GetWorkspaceTemplateName() string` + +GetWorkspaceTemplateName returns the WorkspaceTemplateName field if non-nil, zero value otherwise. + +### GetWorkspaceTemplateNameOk + +`func (o *PrebuildDTO) GetWorkspaceTemplateNameOk() (*string, bool)` + +GetWorkspaceTemplateNameOk returns a tuple with the WorkspaceTemplateName field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetWorkspaceTemplateName + +`func (o *PrebuildDTO) SetWorkspaceTemplateName(v string)` + +SetWorkspaceTemplateName sets WorkspaceTemplateName field to given value. + + [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pkg/apiclient/docs/ProfileAPI.md b/pkg/apiclient/docs/ProfileAPI.md deleted file mode 100644 index 45e45d2fad..0000000000 --- a/pkg/apiclient/docs/ProfileAPI.md +++ /dev/null @@ -1,195 +0,0 @@ -# \ProfileAPI - -All URIs are relative to *http://localhost:3986* - -Method | HTTP request | Description -------------- | ------------- | ------------- -[**DeleteProfileData**](ProfileAPI.md#DeleteProfileData) | **Delete** /profile | Delete profile data -[**GetProfileData**](ProfileAPI.md#GetProfileData) | **Get** /profile | Get profile data -[**SetProfileData**](ProfileAPI.md#SetProfileData) | **Put** /profile | Set profile data - - - -## DeleteProfileData - -> DeleteProfileData(ctx).Execute() - -Delete profile data - - - -### Example - -```go -package main - -import ( - "context" - "fmt" - "os" - openapiclient "github.com/GIT_USER_ID/GIT_REPO_ID/apiclient" -) - -func main() { - - configuration := openapiclient.NewConfiguration() - apiClient := openapiclient.NewAPIClient(configuration) - r, err := apiClient.ProfileAPI.DeleteProfileData(context.Background()).Execute() - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `ProfileAPI.DeleteProfileData``: %v\n", err) - fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - } -} -``` - -### Path Parameters - -This endpoint does not need any parameter. - -### Other Parameters - -Other parameters are passed through a pointer to a apiDeleteProfileDataRequest struct via the builder pattern - - -### Return type - - (empty response body) - -### Authorization - -[Bearer](../README.md#Bearer) - -### HTTP request headers - -- **Content-Type**: Not defined -- **Accept**: Not defined - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) -[[Back to Model list]](../README.md#documentation-for-models) -[[Back to README]](../README.md) - - -## GetProfileData - -> ProfileData GetProfileData(ctx).Execute() - -Get profile data - - - -### Example - -```go -package main - -import ( - "context" - "fmt" - "os" - openapiclient "github.com/GIT_USER_ID/GIT_REPO_ID/apiclient" -) - -func main() { - - configuration := openapiclient.NewConfiguration() - apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.ProfileAPI.GetProfileData(context.Background()).Execute() - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `ProfileAPI.GetProfileData``: %v\n", err) - fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - } - // response from `GetProfileData`: ProfileData - fmt.Fprintf(os.Stdout, "Response from `ProfileAPI.GetProfileData`: %v\n", resp) -} -``` - -### Path Parameters - -This endpoint does not need any parameter. - -### Other Parameters - -Other parameters are passed through a pointer to a apiGetProfileDataRequest struct via the builder pattern - - -### Return type - -[**ProfileData**](ProfileData.md) - -### Authorization - -[Bearer](../README.md#Bearer) - -### HTTP request headers - -- **Content-Type**: Not defined -- **Accept**: */* - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) -[[Back to Model list]](../README.md#documentation-for-models) -[[Back to README]](../README.md) - - -## SetProfileData - -> SetProfileData(ctx).ProfileData(profileData).Execute() - -Set profile data - - - -### Example - -```go -package main - -import ( - "context" - "fmt" - "os" - openapiclient "github.com/GIT_USER_ID/GIT_REPO_ID/apiclient" -) - -func main() { - profileData := *openapiclient.NewProfileData(map[string]string{"key": "Inner_example"}) // ProfileData | Profile data - - configuration := openapiclient.NewConfiguration() - apiClient := openapiclient.NewAPIClient(configuration) - r, err := apiClient.ProfileAPI.SetProfileData(context.Background()).ProfileData(profileData).Execute() - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `ProfileAPI.SetProfileData``: %v\n", err) - fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - } -} -``` - -### Path Parameters - - - -### Other Parameters - -Other parameters are passed through a pointer to a apiSetProfileDataRequest struct via the builder pattern - - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **profileData** | [**ProfileData**](ProfileData.md) | Profile data | - -### Return type - - (empty response body) - -### Authorization - -[Bearer](../README.md#Bearer) - -### HTTP request headers - -- **Content-Type**: application/json -- **Accept**: Not defined - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) -[[Back to Model list]](../README.md#documentation-for-models) -[[Back to README]](../README.md) - diff --git a/pkg/apiclient/docs/ProfileData.md b/pkg/apiclient/docs/ProfileData.md deleted file mode 100644 index eaa420b011..0000000000 --- a/pkg/apiclient/docs/ProfileData.md +++ /dev/null @@ -1,51 +0,0 @@ -# ProfileData - -## Properties - -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**EnvVars** | **map[string]string** | | - -## Methods - -### NewProfileData - -`func NewProfileData(envVars map[string]string, ) *ProfileData` - -NewProfileData instantiates a new ProfileData object -This constructor will assign default values to properties that have it defined, -and makes sure properties required by API are set, but the set of arguments -will change when the set of required properties is changed - -### NewProfileDataWithDefaults - -`func NewProfileDataWithDefaults() *ProfileData` - -NewProfileDataWithDefaults instantiates a new ProfileData object -This constructor will only assign default values to properties that have it defined, -but it doesn't guarantee that properties required by API are set - -### GetEnvVars - -`func (o *ProfileData) GetEnvVars() map[string]string` - -GetEnvVars returns the EnvVars field if non-nil, zero value otherwise. - -### GetEnvVarsOk - -`func (o *ProfileData) GetEnvVarsOk() (*map[string]string, bool)` - -GetEnvVarsOk returns a tuple with the EnvVars field if it's non-nil, zero value otherwise -and a boolean to check if the value has been set. - -### SetEnvVars - -`func (o *ProfileData) SetEnvVars(v map[string]string)` - -SetEnvVars sets EnvVars field to given value. - - - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/pkg/apiclient/docs/Project.md b/pkg/apiclient/docs/Project.md deleted file mode 100644 index 1e95900872..0000000000 --- a/pkg/apiclient/docs/Project.md +++ /dev/null @@ -1,255 +0,0 @@ -# Project - -## Properties - -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**BuildConfig** | Pointer to [**BuildConfig**](BuildConfig.md) | | [optional] -**EnvVars** | **map[string]string** | | -**GitProviderConfigId** | Pointer to **string** | | [optional] -**Image** | **string** | | -**Name** | **string** | | -**Repository** | [**GitRepository**](GitRepository.md) | | -**State** | Pointer to [**ProjectState**](ProjectState.md) | | [optional] -**Target** | **string** | | -**User** | **string** | | -**WorkspaceId** | **string** | | - -## Methods - -### NewProject - -`func NewProject(envVars map[string]string, image string, name string, repository GitRepository, target string, user string, workspaceId string, ) *Project` - -NewProject instantiates a new Project object -This constructor will assign default values to properties that have it defined, -and makes sure properties required by API are set, but the set of arguments -will change when the set of required properties is changed - -### NewProjectWithDefaults - -`func NewProjectWithDefaults() *Project` - -NewProjectWithDefaults instantiates a new Project object -This constructor will only assign default values to properties that have it defined, -but it doesn't guarantee that properties required by API are set - -### GetBuildConfig - -`func (o *Project) GetBuildConfig() BuildConfig` - -GetBuildConfig returns the BuildConfig field if non-nil, zero value otherwise. - -### GetBuildConfigOk - -`func (o *Project) GetBuildConfigOk() (*BuildConfig, bool)` - -GetBuildConfigOk returns a tuple with the BuildConfig field if it's non-nil, zero value otherwise -and a boolean to check if the value has been set. - -### SetBuildConfig - -`func (o *Project) SetBuildConfig(v BuildConfig)` - -SetBuildConfig sets BuildConfig field to given value. - -### HasBuildConfig - -`func (o *Project) HasBuildConfig() bool` - -HasBuildConfig returns a boolean if a field has been set. - -### GetEnvVars - -`func (o *Project) GetEnvVars() map[string]string` - -GetEnvVars returns the EnvVars field if non-nil, zero value otherwise. - -### GetEnvVarsOk - -`func (o *Project) GetEnvVarsOk() (*map[string]string, bool)` - -GetEnvVarsOk returns a tuple with the EnvVars field if it's non-nil, zero value otherwise -and a boolean to check if the value has been set. - -### SetEnvVars - -`func (o *Project) SetEnvVars(v map[string]string)` - -SetEnvVars sets EnvVars field to given value. - - -### GetGitProviderConfigId - -`func (o *Project) GetGitProviderConfigId() string` - -GetGitProviderConfigId returns the GitProviderConfigId field if non-nil, zero value otherwise. - -### GetGitProviderConfigIdOk - -`func (o *Project) GetGitProviderConfigIdOk() (*string, bool)` - -GetGitProviderConfigIdOk returns a tuple with the GitProviderConfigId field if it's non-nil, zero value otherwise -and a boolean to check if the value has been set. - -### SetGitProviderConfigId - -`func (o *Project) SetGitProviderConfigId(v string)` - -SetGitProviderConfigId sets GitProviderConfigId field to given value. - -### HasGitProviderConfigId - -`func (o *Project) HasGitProviderConfigId() bool` - -HasGitProviderConfigId returns a boolean if a field has been set. - -### GetImage - -`func (o *Project) GetImage() string` - -GetImage returns the Image field if non-nil, zero value otherwise. - -### GetImageOk - -`func (o *Project) GetImageOk() (*string, bool)` - -GetImageOk returns a tuple with the Image field if it's non-nil, zero value otherwise -and a boolean to check if the value has been set. - -### SetImage - -`func (o *Project) SetImage(v string)` - -SetImage sets Image field to given value. - - -### GetName - -`func (o *Project) GetName() string` - -GetName returns the Name field if non-nil, zero value otherwise. - -### GetNameOk - -`func (o *Project) GetNameOk() (*string, bool)` - -GetNameOk returns a tuple with the Name field if it's non-nil, zero value otherwise -and a boolean to check if the value has been set. - -### SetName - -`func (o *Project) SetName(v string)` - -SetName sets Name field to given value. - - -### GetRepository - -`func (o *Project) GetRepository() GitRepository` - -GetRepository returns the Repository field if non-nil, zero value otherwise. - -### GetRepositoryOk - -`func (o *Project) GetRepositoryOk() (*GitRepository, bool)` - -GetRepositoryOk returns a tuple with the Repository field if it's non-nil, zero value otherwise -and a boolean to check if the value has been set. - -### SetRepository - -`func (o *Project) SetRepository(v GitRepository)` - -SetRepository sets Repository field to given value. - - -### GetState - -`func (o *Project) GetState() ProjectState` - -GetState returns the State field if non-nil, zero value otherwise. - -### GetStateOk - -`func (o *Project) GetStateOk() (*ProjectState, bool)` - -GetStateOk returns a tuple with the State field if it's non-nil, zero value otherwise -and a boolean to check if the value has been set. - -### SetState - -`func (o *Project) SetState(v ProjectState)` - -SetState sets State field to given value. - -### HasState - -`func (o *Project) HasState() bool` - -HasState returns a boolean if a field has been set. - -### GetTarget - -`func (o *Project) GetTarget() string` - -GetTarget returns the Target field if non-nil, zero value otherwise. - -### GetTargetOk - -`func (o *Project) GetTargetOk() (*string, bool)` - -GetTargetOk returns a tuple with the Target field if it's non-nil, zero value otherwise -and a boolean to check if the value has been set. - -### SetTarget - -`func (o *Project) SetTarget(v string)` - -SetTarget sets Target field to given value. - - -### GetUser - -`func (o *Project) GetUser() string` - -GetUser returns the User field if non-nil, zero value otherwise. - -### GetUserOk - -`func (o *Project) GetUserOk() (*string, bool)` - -GetUserOk returns a tuple with the User field if it's non-nil, zero value otherwise -and a boolean to check if the value has been set. - -### SetUser - -`func (o *Project) SetUser(v string)` - -SetUser sets User field to given value. - - -### GetWorkspaceId - -`func (o *Project) GetWorkspaceId() string` - -GetWorkspaceId returns the WorkspaceId field if non-nil, zero value otherwise. - -### GetWorkspaceIdOk - -`func (o *Project) GetWorkspaceIdOk() (*string, bool)` - -GetWorkspaceIdOk returns a tuple with the WorkspaceId field if it's non-nil, zero value otherwise -and a boolean to check if the value has been set. - -### SetWorkspaceId - -`func (o *Project) SetWorkspaceId(v string)` - -SetWorkspaceId sets WorkspaceId field to given value. - - - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/pkg/apiclient/docs/ProjectInfo.md b/pkg/apiclient/docs/ProjectInfo.md deleted file mode 100644 index 78cd60e751..0000000000 --- a/pkg/apiclient/docs/ProjectInfo.md +++ /dev/null @@ -1,140 +0,0 @@ -# ProjectInfo - -## Properties - -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**Created** | **string** | | -**IsRunning** | **bool** | | -**Name** | **string** | | -**ProviderMetadata** | Pointer to **string** | | [optional] -**WorkspaceId** | **string** | | - -## Methods - -### NewProjectInfo - -`func NewProjectInfo(created string, isRunning bool, name string, workspaceId string, ) *ProjectInfo` - -NewProjectInfo instantiates a new ProjectInfo object -This constructor will assign default values to properties that have it defined, -and makes sure properties required by API are set, but the set of arguments -will change when the set of required properties is changed - -### NewProjectInfoWithDefaults - -`func NewProjectInfoWithDefaults() *ProjectInfo` - -NewProjectInfoWithDefaults instantiates a new ProjectInfo object -This constructor will only assign default values to properties that have it defined, -but it doesn't guarantee that properties required by API are set - -### GetCreated - -`func (o *ProjectInfo) GetCreated() string` - -GetCreated returns the Created field if non-nil, zero value otherwise. - -### GetCreatedOk - -`func (o *ProjectInfo) GetCreatedOk() (*string, bool)` - -GetCreatedOk returns a tuple with the Created field if it's non-nil, zero value otherwise -and a boolean to check if the value has been set. - -### SetCreated - -`func (o *ProjectInfo) SetCreated(v string)` - -SetCreated sets Created field to given value. - - -### GetIsRunning - -`func (o *ProjectInfo) GetIsRunning() bool` - -GetIsRunning returns the IsRunning field if non-nil, zero value otherwise. - -### GetIsRunningOk - -`func (o *ProjectInfo) GetIsRunningOk() (*bool, bool)` - -GetIsRunningOk returns a tuple with the IsRunning field if it's non-nil, zero value otherwise -and a boolean to check if the value has been set. - -### SetIsRunning - -`func (o *ProjectInfo) SetIsRunning(v bool)` - -SetIsRunning sets IsRunning field to given value. - - -### GetName - -`func (o *ProjectInfo) GetName() string` - -GetName returns the Name field if non-nil, zero value otherwise. - -### GetNameOk - -`func (o *ProjectInfo) GetNameOk() (*string, bool)` - -GetNameOk returns a tuple with the Name field if it's non-nil, zero value otherwise -and a boolean to check if the value has been set. - -### SetName - -`func (o *ProjectInfo) SetName(v string)` - -SetName sets Name field to given value. - - -### GetProviderMetadata - -`func (o *ProjectInfo) GetProviderMetadata() string` - -GetProviderMetadata returns the ProviderMetadata field if non-nil, zero value otherwise. - -### GetProviderMetadataOk - -`func (o *ProjectInfo) GetProviderMetadataOk() (*string, bool)` - -GetProviderMetadataOk returns a tuple with the ProviderMetadata field if it's non-nil, zero value otherwise -and a boolean to check if the value has been set. - -### SetProviderMetadata - -`func (o *ProjectInfo) SetProviderMetadata(v string)` - -SetProviderMetadata sets ProviderMetadata field to given value. - -### HasProviderMetadata - -`func (o *ProjectInfo) HasProviderMetadata() bool` - -HasProviderMetadata returns a boolean if a field has been set. - -### GetWorkspaceId - -`func (o *ProjectInfo) GetWorkspaceId() string` - -GetWorkspaceId returns the WorkspaceId field if non-nil, zero value otherwise. - -### GetWorkspaceIdOk - -`func (o *ProjectInfo) GetWorkspaceIdOk() (*string, bool)` - -GetWorkspaceIdOk returns a tuple with the WorkspaceId field if it's non-nil, zero value otherwise -and a boolean to check if the value has been set. - -### SetWorkspaceId - -`func (o *ProjectInfo) SetWorkspaceId(v string)` - -SetWorkspaceId sets WorkspaceId field to given value. - - - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/pkg/apiclient/docs/Provider.md b/pkg/apiclient/docs/Provider.md deleted file mode 100644 index fae62455f1..0000000000 --- a/pkg/apiclient/docs/Provider.md +++ /dev/null @@ -1,98 +0,0 @@ -# Provider - -## Properties - -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**Label** | Pointer to **string** | | [optional] -**Name** | **string** | | -**Version** | **string** | | - -## Methods - -### NewProvider - -`func NewProvider(name string, version string, ) *Provider` - -NewProvider instantiates a new Provider object -This constructor will assign default values to properties that have it defined, -and makes sure properties required by API are set, but the set of arguments -will change when the set of required properties is changed - -### NewProviderWithDefaults - -`func NewProviderWithDefaults() *Provider` - -NewProviderWithDefaults instantiates a new Provider object -This constructor will only assign default values to properties that have it defined, -but it doesn't guarantee that properties required by API are set - -### GetLabel - -`func (o *Provider) GetLabel() string` - -GetLabel returns the Label field if non-nil, zero value otherwise. - -### GetLabelOk - -`func (o *Provider) GetLabelOk() (*string, bool)` - -GetLabelOk returns a tuple with the Label field if it's non-nil, zero value otherwise -and a boolean to check if the value has been set. - -### SetLabel - -`func (o *Provider) SetLabel(v string)` - -SetLabel sets Label field to given value. - -### HasLabel - -`func (o *Provider) HasLabel() bool` - -HasLabel returns a boolean if a field has been set. - -### GetName - -`func (o *Provider) GetName() string` - -GetName returns the Name field if non-nil, zero value otherwise. - -### GetNameOk - -`func (o *Provider) GetNameOk() (*string, bool)` - -GetNameOk returns a tuple with the Name field if it's non-nil, zero value otherwise -and a boolean to check if the value has been set. - -### SetName - -`func (o *Provider) SetName(v string)` - -SetName sets Name field to given value. - - -### GetVersion - -`func (o *Provider) GetVersion() string` - -GetVersion returns the Version field if non-nil, zero value otherwise. - -### GetVersionOk - -`func (o *Provider) GetVersionOk() (*string, bool)` - -GetVersionOk returns a tuple with the Version field if it's non-nil, zero value otherwise -and a boolean to check if the value has been set. - -### SetVersion - -`func (o *Provider) SetVersion(v string)` - -SetVersion sets Version field to given value. - - - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/pkg/apiclient/docs/ProviderAPI.md b/pkg/apiclient/docs/ProviderAPI.md index 748cea7525..48bb6227af 100644 --- a/pkg/apiclient/docs/ProviderAPI.md +++ b/pkg/apiclient/docs/ProviderAPI.md @@ -4,18 +4,20 @@ All URIs are relative to *http://localhost:3986* Method | HTTP request | Description ------------- | ------------- | ------------- -[**GetTargetManifest**](ProviderAPI.md#GetTargetManifest) | **Get** /provider/{provider}/target-manifest | Get provider target manifest -[**InstallProvider**](ProviderAPI.md#InstallProvider) | **Post** /provider/install | Install a provider -[**ListProviders**](ProviderAPI.md#ListProviders) | **Get** /provider | List providers -[**UninstallProvider**](ProviderAPI.md#UninstallProvider) | **Post** /provider/{provider}/uninstall | Uninstall a provider +[**GetRunnerProviders**](ProviderAPI.md#GetRunnerProviders) | **Get** /runner/{runnerId}/provider | Get runner providers +[**InstallProvider**](ProviderAPI.md#InstallProvider) | **Post** /runner/{runnerId}/provider/{providerName}/install | Install provider +[**ListProviders**](ProviderAPI.md#ListProviders) | **Get** /runner/provider | List providers +[**ListProvidersForInstall**](ProviderAPI.md#ListProvidersForInstall) | **Get** /runner/provider/for-install | List providers available for installation +[**UninstallProvider**](ProviderAPI.md#UninstallProvider) | **Post** /runner/{runnerId}/provider/{providerName}/uninstall | Uninstall provider +[**UpdateProvider**](ProviderAPI.md#UpdateProvider) | **Post** /runner/{runnerId}/provider/{providerName}/update | Update provider -## GetTargetManifest +## GetRunnerProviders -> map[string]ProviderProviderTargetProperty GetTargetManifest(ctx, provider).Execute() +> []ProviderInfo GetRunnerProviders(ctx, runnerId).Execute() -Get provider target manifest +Get runner providers @@ -32,17 +34,17 @@ import ( ) func main() { - provider := "provider_example" // string | Provider name + runnerId := "runnerId_example" // string | Runner ID configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.ProviderAPI.GetTargetManifest(context.Background(), provider).Execute() + resp, r, err := apiClient.ProviderAPI.GetRunnerProviders(context.Background(), runnerId).Execute() if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `ProviderAPI.GetTargetManifest``: %v\n", err) + fmt.Fprintf(os.Stderr, "Error when calling `ProviderAPI.GetRunnerProviders``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) } - // response from `GetTargetManifest`: map[string]ProviderProviderTargetProperty - fmt.Fprintf(os.Stdout, "Response from `ProviderAPI.GetTargetManifest`: %v\n", resp) + // response from `GetRunnerProviders`: []ProviderInfo + fmt.Fprintf(os.Stdout, "Response from `ProviderAPI.GetRunnerProviders`: %v\n", resp) } ``` @@ -52,11 +54,11 @@ func main() { Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. -**provider** | **string** | Provider name | +**runnerId** | **string** | Runner ID | ### Other Parameters -Other parameters are passed through a pointer to a apiGetTargetManifestRequest struct via the builder pattern +Other parameters are passed through a pointer to a apiGetRunnerProvidersRequest struct via the builder pattern Name | Type | Description | Notes @@ -65,7 +67,7 @@ Name | Type | Description | Notes ### Return type -[**map[string]ProviderProviderTargetProperty**](ProviderProviderTargetProperty.md) +[**[]ProviderInfo**](ProviderInfo.md) ### Authorization @@ -74,7 +76,7 @@ Name | Type | Description | Notes ### HTTP request headers - **Content-Type**: Not defined -- **Accept**: */* +- **Accept**: application/json [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) @@ -83,9 +85,9 @@ Name | Type | Description | Notes ## InstallProvider -> InstallProvider(ctx).Provider(provider).Execute() +> InstallProvider(ctx, runnerId, providerName).ProviderVersion(providerVersion).Execute() -Install a provider +Install provider @@ -102,11 +104,13 @@ import ( ) func main() { - provider := *openapiclient.NewInstallProviderRequest(map[string]string{"key": "Inner_example"}, "Name_example") // InstallProviderRequest | Provider to install + runnerId := "runnerId_example" // string | Runner ID + providerName := "providerName_example" // string | Provider name + providerVersion := "providerVersion_example" // string | Provider version - defaults to 'latest' (optional) configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - r, err := apiClient.ProviderAPI.InstallProvider(context.Background()).Provider(provider).Execute() + r, err := apiClient.ProviderAPI.InstallProvider(context.Background(), runnerId, providerName).ProviderVersion(providerVersion).Execute() if err != nil { fmt.Fprintf(os.Stderr, "Error when calling `ProviderAPI.InstallProvider``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) @@ -117,6 +121,11 @@ func main() { ### Path Parameters +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- +**ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. +**runnerId** | **string** | Runner ID | +**providerName** | **string** | Provider name | ### Other Parameters @@ -125,7 +134,9 @@ Other parameters are passed through a pointer to a apiInstallProviderRequest str Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - **provider** | [**InstallProviderRequest**](InstallProviderRequest.md) | Provider to install | + + + **providerVersion** | **string** | Provider version - defaults to 'latest' | ### Return type @@ -137,7 +148,7 @@ Name | Type | Description | Notes ### HTTP request headers -- **Content-Type**: application/json +- **Content-Type**: Not defined - **Accept**: Not defined [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) @@ -147,7 +158,7 @@ Name | Type | Description | Notes ## ListProviders -> []Provider ListProviders(ctx).Execute() +> []ProviderInfo ListProviders(ctx).RunnerId(runnerId).Execute() List providers @@ -166,31 +177,97 @@ import ( ) func main() { + runnerId := "runnerId_example" // string | Runner ID (optional) configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.ProviderAPI.ListProviders(context.Background()).Execute() + resp, r, err := apiClient.ProviderAPI.ListProviders(context.Background()).RunnerId(runnerId).Execute() if err != nil { fmt.Fprintf(os.Stderr, "Error when calling `ProviderAPI.ListProviders``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) } - // response from `ListProviders`: []Provider + // response from `ListProviders`: []ProviderInfo fmt.Fprintf(os.Stdout, "Response from `ProviderAPI.ListProviders`: %v\n", resp) } ``` ### Path Parameters -This endpoint does not need any parameter. + ### Other Parameters Other parameters are passed through a pointer to a apiListProvidersRequest struct via the builder pattern +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **runnerId** | **string** | Runner ID | + +### Return type + +[**[]ProviderInfo**](ProviderInfo.md) + +### Authorization + +[Bearer](../README.md#Bearer) + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) +[[Back to Model list]](../README.md#documentation-for-models) +[[Back to README]](../README.md) + + +## ListProvidersForInstall + +> []ProviderDTO ListProvidersForInstall(ctx).Execute() + +List providers available for installation + + + +### Example + +```go +package main + +import ( + "context" + "fmt" + "os" + openapiclient "github.com/GIT_USER_ID/GIT_REPO_ID/apiclient" +) + +func main() { + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.ProviderAPI.ListProvidersForInstall(context.Background()).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `ProviderAPI.ListProvidersForInstall``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `ListProvidersForInstall`: []ProviderDTO + fmt.Fprintf(os.Stdout, "Response from `ProviderAPI.ListProvidersForInstall`: %v\n", resp) +} +``` + +### Path Parameters + +This endpoint does not need any parameter. + +### Other Parameters + +Other parameters are passed through a pointer to a apiListProvidersForInstallRequest struct via the builder pattern + + ### Return type -[**[]Provider**](Provider.md) +[**[]ProviderDTO**](ProviderDTO.md) ### Authorization @@ -208,9 +285,9 @@ Other parameters are passed through a pointer to a apiListProvidersRequest struc ## UninstallProvider -> UninstallProvider(ctx, provider).Execute() +> UninstallProvider(ctx, runnerId, providerName).Execute() -Uninstall a provider +Uninstall provider @@ -227,11 +304,12 @@ import ( ) func main() { - provider := "provider_example" // string | Provider to uninstall + runnerId := "runnerId_example" // string | Runner ID + providerName := "providerName_example" // string | Provider name configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - r, err := apiClient.ProviderAPI.UninstallProvider(context.Background(), provider).Execute() + r, err := apiClient.ProviderAPI.UninstallProvider(context.Background(), runnerId, providerName).Execute() if err != nil { fmt.Fprintf(os.Stderr, "Error when calling `ProviderAPI.UninstallProvider``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) @@ -245,7 +323,8 @@ func main() { Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. -**provider** | **string** | Provider to uninstall | +**runnerId** | **string** | Runner ID | +**providerName** | **string** | Provider name | ### Other Parameters @@ -256,6 +335,80 @@ Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- + +### Return type + + (empty response body) + +### Authorization + +[Bearer](../README.md#Bearer) + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: Not defined + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) +[[Back to Model list]](../README.md#documentation-for-models) +[[Back to README]](../README.md) + + +## UpdateProvider + +> UpdateProvider(ctx, runnerId, providerName).ProviderVersion(providerVersion).Execute() + +Update provider + + + +### Example + +```go +package main + +import ( + "context" + "fmt" + "os" + openapiclient "github.com/GIT_USER_ID/GIT_REPO_ID/apiclient" +) + +func main() { + runnerId := "runnerId_example" // string | Runner ID + providerName := "providerName_example" // string | Provider name + providerVersion := "providerVersion_example" // string | Provider version - defaults to 'latest' (optional) + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + r, err := apiClient.ProviderAPI.UpdateProvider(context.Background(), runnerId, providerName).ProviderVersion(providerVersion).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `ProviderAPI.UpdateProvider``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } +} +``` + +### Path Parameters + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- +**ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. +**runnerId** | **string** | Runner ID | +**providerName** | **string** | Provider name | + +### Other Parameters + +Other parameters are passed through a pointer to a apiUpdateProviderRequest struct via the builder pattern + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + + + **providerVersion** | **string** | Provider version - defaults to 'latest' | + ### Return type (empty response body) diff --git a/pkg/apiclient/docs/ProviderProviderInfo.md b/pkg/apiclient/docs/ProviderDTO.md similarity index 58% rename from pkg/apiclient/docs/ProviderProviderInfo.md rename to pkg/apiclient/docs/ProviderDTO.md index a20bd6d5a0..9516db5ad2 100644 --- a/pkg/apiclient/docs/ProviderProviderInfo.md +++ b/pkg/apiclient/docs/ProviderDTO.md @@ -1,93 +1,114 @@ -# ProviderProviderInfo +# ProviderDTO ## Properties Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- **Label** | Pointer to **string** | | [optional] +**Latest** | **bool** | | **Name** | **string** | | **Version** | **string** | | ## Methods -### NewProviderProviderInfo +### NewProviderDTO -`func NewProviderProviderInfo(name string, version string, ) *ProviderProviderInfo` +`func NewProviderDTO(latest bool, name string, version string, ) *ProviderDTO` -NewProviderProviderInfo instantiates a new ProviderProviderInfo object +NewProviderDTO instantiates a new ProviderDTO object This constructor will assign default values to properties that have it defined, and makes sure properties required by API are set, but the set of arguments will change when the set of required properties is changed -### NewProviderProviderInfoWithDefaults +### NewProviderDTOWithDefaults -`func NewProviderProviderInfoWithDefaults() *ProviderProviderInfo` +`func NewProviderDTOWithDefaults() *ProviderDTO` -NewProviderProviderInfoWithDefaults instantiates a new ProviderProviderInfo object +NewProviderDTOWithDefaults instantiates a new ProviderDTO object This constructor will only assign default values to properties that have it defined, but it doesn't guarantee that properties required by API are set ### GetLabel -`func (o *ProviderProviderInfo) GetLabel() string` +`func (o *ProviderDTO) GetLabel() string` GetLabel returns the Label field if non-nil, zero value otherwise. ### GetLabelOk -`func (o *ProviderProviderInfo) GetLabelOk() (*string, bool)` +`func (o *ProviderDTO) GetLabelOk() (*string, bool)` GetLabelOk returns a tuple with the Label field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. ### SetLabel -`func (o *ProviderProviderInfo) SetLabel(v string)` +`func (o *ProviderDTO) SetLabel(v string)` SetLabel sets Label field to given value. ### HasLabel -`func (o *ProviderProviderInfo) HasLabel() bool` +`func (o *ProviderDTO) HasLabel() bool` HasLabel returns a boolean if a field has been set. +### GetLatest + +`func (o *ProviderDTO) GetLatest() bool` + +GetLatest returns the Latest field if non-nil, zero value otherwise. + +### GetLatestOk + +`func (o *ProviderDTO) GetLatestOk() (*bool, bool)` + +GetLatestOk returns a tuple with the Latest field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetLatest + +`func (o *ProviderDTO) SetLatest(v bool)` + +SetLatest sets Latest field to given value. + + ### GetName -`func (o *ProviderProviderInfo) GetName() string` +`func (o *ProviderDTO) GetName() string` GetName returns the Name field if non-nil, zero value otherwise. ### GetNameOk -`func (o *ProviderProviderInfo) GetNameOk() (*string, bool)` +`func (o *ProviderDTO) GetNameOk() (*string, bool)` GetNameOk returns a tuple with the Name field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. ### SetName -`func (o *ProviderProviderInfo) SetName(v string)` +`func (o *ProviderDTO) SetName(v string)` SetName sets Name field to given value. ### GetVersion -`func (o *ProviderProviderInfo) GetVersion() string` +`func (o *ProviderDTO) GetVersion() string` GetVersion returns the Version field if non-nil, zero value otherwise. ### GetVersionOk -`func (o *ProviderProviderInfo) GetVersionOk() (*string, bool)` +`func (o *ProviderDTO) GetVersionOk() (*string, bool)` GetVersionOk returns a tuple with the Version field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. ### SetVersion -`func (o *ProviderProviderInfo) SetVersion(v string)` +`func (o *ProviderDTO) SetVersion(v string)` SetVersion sets Version field to given value. diff --git a/pkg/apiclient/docs/ProviderInfo.md b/pkg/apiclient/docs/ProviderInfo.md new file mode 100644 index 0000000000..66f4004039 --- /dev/null +++ b/pkg/apiclient/docs/ProviderInfo.md @@ -0,0 +1,187 @@ +# ProviderInfo + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**AgentlessTarget** | Pointer to **bool** | | [optional] +**Label** | Pointer to **string** | | [optional] +**Name** | **string** | | +**RunnerId** | **string** | | +**RunnerName** | **string** | | +**TargetConfigManifest** | [**map[string]TargetConfigProperty**](TargetConfigProperty.md) | | +**Version** | **string** | | + +## Methods + +### NewProviderInfo + +`func NewProviderInfo(name string, runnerId string, runnerName string, targetConfigManifest map[string]TargetConfigProperty, version string, ) *ProviderInfo` + +NewProviderInfo instantiates a new ProviderInfo object +This constructor will assign default values to properties that have it defined, +and makes sure properties required by API are set, but the set of arguments +will change when the set of required properties is changed + +### NewProviderInfoWithDefaults + +`func NewProviderInfoWithDefaults() *ProviderInfo` + +NewProviderInfoWithDefaults instantiates a new ProviderInfo object +This constructor will only assign default values to properties that have it defined, +but it doesn't guarantee that properties required by API are set + +### GetAgentlessTarget + +`func (o *ProviderInfo) GetAgentlessTarget() bool` + +GetAgentlessTarget returns the AgentlessTarget field if non-nil, zero value otherwise. + +### GetAgentlessTargetOk + +`func (o *ProviderInfo) GetAgentlessTargetOk() (*bool, bool)` + +GetAgentlessTargetOk returns a tuple with the AgentlessTarget field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetAgentlessTarget + +`func (o *ProviderInfo) SetAgentlessTarget(v bool)` + +SetAgentlessTarget sets AgentlessTarget field to given value. + +### HasAgentlessTarget + +`func (o *ProviderInfo) HasAgentlessTarget() bool` + +HasAgentlessTarget returns a boolean if a field has been set. + +### GetLabel + +`func (o *ProviderInfo) GetLabel() string` + +GetLabel returns the Label field if non-nil, zero value otherwise. + +### GetLabelOk + +`func (o *ProviderInfo) GetLabelOk() (*string, bool)` + +GetLabelOk returns a tuple with the Label field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetLabel + +`func (o *ProviderInfo) SetLabel(v string)` + +SetLabel sets Label field to given value. + +### HasLabel + +`func (o *ProviderInfo) HasLabel() bool` + +HasLabel returns a boolean if a field has been set. + +### GetName + +`func (o *ProviderInfo) GetName() string` + +GetName returns the Name field if non-nil, zero value otherwise. + +### GetNameOk + +`func (o *ProviderInfo) GetNameOk() (*string, bool)` + +GetNameOk returns a tuple with the Name field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetName + +`func (o *ProviderInfo) SetName(v string)` + +SetName sets Name field to given value. + + +### GetRunnerId + +`func (o *ProviderInfo) GetRunnerId() string` + +GetRunnerId returns the RunnerId field if non-nil, zero value otherwise. + +### GetRunnerIdOk + +`func (o *ProviderInfo) GetRunnerIdOk() (*string, bool)` + +GetRunnerIdOk returns a tuple with the RunnerId field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetRunnerId + +`func (o *ProviderInfo) SetRunnerId(v string)` + +SetRunnerId sets RunnerId field to given value. + + +### GetRunnerName + +`func (o *ProviderInfo) GetRunnerName() string` + +GetRunnerName returns the RunnerName field if non-nil, zero value otherwise. + +### GetRunnerNameOk + +`func (o *ProviderInfo) GetRunnerNameOk() (*string, bool)` + +GetRunnerNameOk returns a tuple with the RunnerName field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetRunnerName + +`func (o *ProviderInfo) SetRunnerName(v string)` + +SetRunnerName sets RunnerName field to given value. + + +### GetTargetConfigManifest + +`func (o *ProviderInfo) GetTargetConfigManifest() map[string]TargetConfigProperty` + +GetTargetConfigManifest returns the TargetConfigManifest field if non-nil, zero value otherwise. + +### GetTargetConfigManifestOk + +`func (o *ProviderInfo) GetTargetConfigManifestOk() (*map[string]TargetConfigProperty, bool)` + +GetTargetConfigManifestOk returns a tuple with the TargetConfigManifest field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetTargetConfigManifest + +`func (o *ProviderInfo) SetTargetConfigManifest(v map[string]TargetConfigProperty)` + +SetTargetConfigManifest sets TargetConfigManifest field to given value. + + +### GetVersion + +`func (o *ProviderInfo) GetVersion() string` + +GetVersion returns the Version field if non-nil, zero value otherwise. + +### GetVersionOk + +`func (o *ProviderInfo) GetVersionOk() (*string, bool)` + +GetVersionOk returns a tuple with the Version field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetVersion + +`func (o *ProviderInfo) SetVersion(v string)` + +SetVersion sets Version field to given value. + + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/pkg/apiclient/docs/ProviderProviderTargetPropertyType.md b/pkg/apiclient/docs/ProviderProviderTargetPropertyType.md deleted file mode 100644 index 39df2ed551..0000000000 --- a/pkg/apiclient/docs/ProviderProviderTargetPropertyType.md +++ /dev/null @@ -1,21 +0,0 @@ -# ProviderProviderTargetPropertyType - -## Enum - - -* `ProviderTargetPropertyTypeString` (value: `"string"`) - -* `ProviderTargetPropertyTypeOption` (value: `"option"`) - -* `ProviderTargetPropertyTypeBoolean` (value: `"boolean"`) - -* `ProviderTargetPropertyTypeInt` (value: `"int"`) - -* `ProviderTargetPropertyTypeFloat` (value: `"float"`) - -* `ProviderTargetPropertyTypeFilePath` (value: `"file-path"`) - - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/pkg/apiclient/docs/ResourceState.md b/pkg/apiclient/docs/ResourceState.md new file mode 100644 index 0000000000..dc3cd6b380 --- /dev/null +++ b/pkg/apiclient/docs/ResourceState.md @@ -0,0 +1,98 @@ +# ResourceState + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Error** | Pointer to **string** | | [optional] +**Name** | [**ModelsResourceStateName**](ModelsResourceStateName.md) | | +**UpdatedAt** | **string** | | + +## Methods + +### NewResourceState + +`func NewResourceState(name ModelsResourceStateName, updatedAt string, ) *ResourceState` + +NewResourceState instantiates a new ResourceState object +This constructor will assign default values to properties that have it defined, +and makes sure properties required by API are set, but the set of arguments +will change when the set of required properties is changed + +### NewResourceStateWithDefaults + +`func NewResourceStateWithDefaults() *ResourceState` + +NewResourceStateWithDefaults instantiates a new ResourceState object +This constructor will only assign default values to properties that have it defined, +but it doesn't guarantee that properties required by API are set + +### GetError + +`func (o *ResourceState) GetError() string` + +GetError returns the Error field if non-nil, zero value otherwise. + +### GetErrorOk + +`func (o *ResourceState) GetErrorOk() (*string, bool)` + +GetErrorOk returns a tuple with the Error field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetError + +`func (o *ResourceState) SetError(v string)` + +SetError sets Error field to given value. + +### HasError + +`func (o *ResourceState) HasError() bool` + +HasError returns a boolean if a field has been set. + +### GetName + +`func (o *ResourceState) GetName() ModelsResourceStateName` + +GetName returns the Name field if non-nil, zero value otherwise. + +### GetNameOk + +`func (o *ResourceState) GetNameOk() (*ModelsResourceStateName, bool)` + +GetNameOk returns a tuple with the Name field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetName + +`func (o *ResourceState) SetName(v ModelsResourceStateName)` + +SetName sets Name field to given value. + + +### GetUpdatedAt + +`func (o *ResourceState) GetUpdatedAt() string` + +GetUpdatedAt returns the UpdatedAt field if non-nil, zero value otherwise. + +### GetUpdatedAtOk + +`func (o *ResourceState) GetUpdatedAtOk() (*string, bool)` + +GetUpdatedAtOk returns a tuple with the UpdatedAt field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetUpdatedAt + +`func (o *ResourceState) SetUpdatedAt(v string)` + +SetUpdatedAt sets UpdatedAt field to given value. + + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/pkg/apiclient/docs/ResourceType.md b/pkg/apiclient/docs/ResourceType.md new file mode 100644 index 0000000000..de1ee5cfba --- /dev/null +++ b/pkg/apiclient/docs/ResourceType.md @@ -0,0 +1,17 @@ +# ResourceType + +## Enum + + +* `ResourceTypeWorkspace` (value: `"workspace"`) + +* `ResourceTypeTarget` (value: `"target"`) + +* `ResourceTypeBuild` (value: `"build"`) + +* `ResourceTypeRunner` (value: `"runner"`) + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/pkg/apiclient/docs/RunnerAPI.md b/pkg/apiclient/docs/RunnerAPI.md new file mode 100644 index 0000000000..cb9ef0dfd9 --- /dev/null +++ b/pkg/apiclient/docs/RunnerAPI.md @@ -0,0 +1,493 @@ +# \RunnerAPI + +All URIs are relative to *http://localhost:3986* + +Method | HTTP request | Description +------------- | ------------- | ------------- +[**CreateRunner**](RunnerAPI.md#CreateRunner) | **Post** /runner | Create a runner +[**DeleteRunner**](RunnerAPI.md#DeleteRunner) | **Delete** /runner/{runnerId} | Delete runner +[**FindRunner**](RunnerAPI.md#FindRunner) | **Get** /runner/{runnerId} | Find a runner +[**ListRunnerJobs**](RunnerAPI.md#ListRunnerJobs) | **Get** /runner/{runnerId}/jobs | List runner jobs +[**ListRunners**](RunnerAPI.md#ListRunners) | **Get** /runner | List runners +[**UpdateJobState**](RunnerAPI.md#UpdateJobState) | **Post** /runner/{runnerId}/jobs/{jobId}/state | Update job state +[**UpdateRunnerMetadata**](RunnerAPI.md#UpdateRunnerMetadata) | **Post** /runner/{runnerId}/metadata | Update runner metadata + + + +## CreateRunner + +> CreateRunnerResultDTO CreateRunner(ctx).Runner(runner).Execute() + +Create a runner + + + +### Example + +```go +package main + +import ( + "context" + "fmt" + "os" + openapiclient "github.com/GIT_USER_ID/GIT_REPO_ID/apiclient" +) + +func main() { + runner := *openapiclient.NewCreateRunnerDTO("Id_example", "Name_example") // CreateRunnerDTO | Runner + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.RunnerAPI.CreateRunner(context.Background()).Runner(runner).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `RunnerAPI.CreateRunner``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `CreateRunner`: CreateRunnerResultDTO + fmt.Fprintf(os.Stdout, "Response from `RunnerAPI.CreateRunner`: %v\n", resp) +} +``` + +### Path Parameters + + + +### Other Parameters + +Other parameters are passed through a pointer to a apiCreateRunnerRequest struct via the builder pattern + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **runner** | [**CreateRunnerDTO**](CreateRunnerDTO.md) | Runner | + +### Return type + +[**CreateRunnerResultDTO**](CreateRunnerResultDTO.md) + +### Authorization + +[Bearer](../README.md#Bearer) + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) +[[Back to Model list]](../README.md#documentation-for-models) +[[Back to README]](../README.md) + + +## DeleteRunner + +> DeleteRunner(ctx, runnerId).Execute() + +Delete runner + + + +### Example + +```go +package main + +import ( + "context" + "fmt" + "os" + openapiclient "github.com/GIT_USER_ID/GIT_REPO_ID/apiclient" +) + +func main() { + runnerId := "runnerId_example" // string | Runner ID + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + r, err := apiClient.RunnerAPI.DeleteRunner(context.Background(), runnerId).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `RunnerAPI.DeleteRunner``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } +} +``` + +### Path Parameters + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- +**ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. +**runnerId** | **string** | Runner ID | + +### Other Parameters + +Other parameters are passed through a pointer to a apiDeleteRunnerRequest struct via the builder pattern + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + + +### Return type + + (empty response body) + +### Authorization + +[Bearer](../README.md#Bearer) + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: Not defined + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) +[[Back to Model list]](../README.md#documentation-for-models) +[[Back to README]](../README.md) + + +## FindRunner + +> RunnerDTO FindRunner(ctx, runnerId).Execute() + +Find a runner + + + +### Example + +```go +package main + +import ( + "context" + "fmt" + "os" + openapiclient "github.com/GIT_USER_ID/GIT_REPO_ID/apiclient" +) + +func main() { + runnerId := "runnerId_example" // string | Runner ID + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.RunnerAPI.FindRunner(context.Background(), runnerId).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `RunnerAPI.FindRunner``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `FindRunner`: RunnerDTO + fmt.Fprintf(os.Stdout, "Response from `RunnerAPI.FindRunner`: %v\n", resp) +} +``` + +### Path Parameters + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- +**ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. +**runnerId** | **string** | Runner ID | + +### Other Parameters + +Other parameters are passed through a pointer to a apiFindRunnerRequest struct via the builder pattern + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + + +### Return type + +[**RunnerDTO**](RunnerDTO.md) + +### Authorization + +[Bearer](../README.md#Bearer) + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) +[[Back to Model list]](../README.md#documentation-for-models) +[[Back to README]](../README.md) + + +## ListRunnerJobs + +> []Job ListRunnerJobs(ctx, runnerId).Execute() + +List runner jobs + + + +### Example + +```go +package main + +import ( + "context" + "fmt" + "os" + openapiclient "github.com/GIT_USER_ID/GIT_REPO_ID/apiclient" +) + +func main() { + runnerId := "runnerId_example" // string | Runner ID + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.RunnerAPI.ListRunnerJobs(context.Background(), runnerId).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `RunnerAPI.ListRunnerJobs``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `ListRunnerJobs`: []Job + fmt.Fprintf(os.Stdout, "Response from `RunnerAPI.ListRunnerJobs`: %v\n", resp) +} +``` + +### Path Parameters + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- +**ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. +**runnerId** | **string** | Runner ID | + +### Other Parameters + +Other parameters are passed through a pointer to a apiListRunnerJobsRequest struct via the builder pattern + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + + +### Return type + +[**[]Job**](Job.md) + +### Authorization + +[Bearer](../README.md#Bearer) + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) +[[Back to Model list]](../README.md#documentation-for-models) +[[Back to README]](../README.md) + + +## ListRunners + +> []RunnerDTO ListRunners(ctx).Execute() + +List runners + + + +### Example + +```go +package main + +import ( + "context" + "fmt" + "os" + openapiclient "github.com/GIT_USER_ID/GIT_REPO_ID/apiclient" +) + +func main() { + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.RunnerAPI.ListRunners(context.Background()).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `RunnerAPI.ListRunners``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `ListRunners`: []RunnerDTO + fmt.Fprintf(os.Stdout, "Response from `RunnerAPI.ListRunners`: %v\n", resp) +} +``` + +### Path Parameters + +This endpoint does not need any parameter. + +### Other Parameters + +Other parameters are passed through a pointer to a apiListRunnersRequest struct via the builder pattern + + +### Return type + +[**[]RunnerDTO**](RunnerDTO.md) + +### Authorization + +[Bearer](../README.md#Bearer) + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) +[[Back to Model list]](../README.md#documentation-for-models) +[[Back to README]](../README.md) + + +## UpdateJobState + +> UpdateJobState(ctx, runnerId, jobId).UpdateJobState(updateJobState).Execute() + +Update job state + + + +### Example + +```go +package main + +import ( + "context" + "fmt" + "os" + openapiclient "github.com/GIT_USER_ID/GIT_REPO_ID/apiclient" +) + +func main() { + runnerId := "runnerId_example" // string | Runner ID + jobId := "jobId_example" // string | Job ID + updateJobState := *openapiclient.NewUpdateJobState(openapiclient.JobState("pending")) // UpdateJobState | Update job state + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + r, err := apiClient.RunnerAPI.UpdateJobState(context.Background(), runnerId, jobId).UpdateJobState(updateJobState).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `RunnerAPI.UpdateJobState``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } +} +``` + +### Path Parameters + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- +**ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. +**runnerId** | **string** | Runner ID | +**jobId** | **string** | Job ID | + +### Other Parameters + +Other parameters are passed through a pointer to a apiUpdateJobStateRequest struct via the builder pattern + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + + + **updateJobState** | [**UpdateJobState**](UpdateJobState.md) | Update job state | + +### Return type + + (empty response body) + +### Authorization + +[Bearer](../README.md#Bearer) + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: Not defined + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) +[[Back to Model list]](../README.md#documentation-for-models) +[[Back to README]](../README.md) + + +## UpdateRunnerMetadata + +> UpdateRunnerMetadata(ctx, runnerId).RunnerMetadata(runnerMetadata).Execute() + +Update runner metadata + + + +### Example + +```go +package main + +import ( + "context" + "fmt" + "os" + openapiclient "github.com/GIT_USER_ID/GIT_REPO_ID/apiclient" +) + +func main() { + runnerId := "runnerId_example" // string | Runner ID + runnerMetadata := *openapiclient.NewUpdateRunnerMetadataDTO([]openapiclient.ProviderInfo{*openapiclient.NewProviderInfo("Name_example", "RunnerId_example", "RunnerName_example", map[string]TargetConfigProperty{"key": *openapiclient.NewTargetConfigProperty()}, "Version_example")}, int32(123)) // UpdateRunnerMetadataDTO | Runner Metadata + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + r, err := apiClient.RunnerAPI.UpdateRunnerMetadata(context.Background(), runnerId).RunnerMetadata(runnerMetadata).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `RunnerAPI.UpdateRunnerMetadata``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } +} +``` + +### Path Parameters + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- +**ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. +**runnerId** | **string** | Runner ID | + +### Other Parameters + +Other parameters are passed through a pointer to a apiUpdateRunnerMetadataRequest struct via the builder pattern + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + + **runnerMetadata** | [**UpdateRunnerMetadataDTO**](UpdateRunnerMetadataDTO.md) | Runner Metadata | + +### Return type + + (empty response body) + +### Authorization + +[Bearer](../README.md#Bearer) + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: Not defined + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) +[[Back to Model list]](../README.md#documentation-for-models) +[[Back to README]](../README.md) + diff --git a/pkg/apiclient/docs/RunnerDTO.md b/pkg/apiclient/docs/RunnerDTO.md new file mode 100644 index 0000000000..75f7d5ac21 --- /dev/null +++ b/pkg/apiclient/docs/RunnerDTO.md @@ -0,0 +1,119 @@ +# RunnerDTO + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Id** | **string** | | +**Metadata** | Pointer to [**RunnerMetadata**](RunnerMetadata.md) | | [optional] +**Name** | **string** | | +**State** | [**ResourceState**](ResourceState.md) | | + +## Methods + +### NewRunnerDTO + +`func NewRunnerDTO(id string, name string, state ResourceState, ) *RunnerDTO` + +NewRunnerDTO instantiates a new RunnerDTO object +This constructor will assign default values to properties that have it defined, +and makes sure properties required by API are set, but the set of arguments +will change when the set of required properties is changed + +### NewRunnerDTOWithDefaults + +`func NewRunnerDTOWithDefaults() *RunnerDTO` + +NewRunnerDTOWithDefaults instantiates a new RunnerDTO object +This constructor will only assign default values to properties that have it defined, +but it doesn't guarantee that properties required by API are set + +### GetId + +`func (o *RunnerDTO) GetId() string` + +GetId returns the Id field if non-nil, zero value otherwise. + +### GetIdOk + +`func (o *RunnerDTO) GetIdOk() (*string, bool)` + +GetIdOk returns a tuple with the Id field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetId + +`func (o *RunnerDTO) SetId(v string)` + +SetId sets Id field to given value. + + +### GetMetadata + +`func (o *RunnerDTO) GetMetadata() RunnerMetadata` + +GetMetadata returns the Metadata field if non-nil, zero value otherwise. + +### GetMetadataOk + +`func (o *RunnerDTO) GetMetadataOk() (*RunnerMetadata, bool)` + +GetMetadataOk returns a tuple with the Metadata field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetMetadata + +`func (o *RunnerDTO) SetMetadata(v RunnerMetadata)` + +SetMetadata sets Metadata field to given value. + +### HasMetadata + +`func (o *RunnerDTO) HasMetadata() bool` + +HasMetadata returns a boolean if a field has been set. + +### GetName + +`func (o *RunnerDTO) GetName() string` + +GetName returns the Name field if non-nil, zero value otherwise. + +### GetNameOk + +`func (o *RunnerDTO) GetNameOk() (*string, bool)` + +GetNameOk returns a tuple with the Name field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetName + +`func (o *RunnerDTO) SetName(v string)` + +SetName sets Name field to given value. + + +### GetState + +`func (o *RunnerDTO) GetState() ResourceState` + +GetState returns the State field if non-nil, zero value otherwise. + +### GetStateOk + +`func (o *RunnerDTO) GetStateOk() (*ResourceState, bool)` + +GetStateOk returns a tuple with the State field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetState + +`func (o *RunnerDTO) SetState(v ResourceState)` + +SetState sets State field to given value. + + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/pkg/apiclient/docs/RunnerMetadata.md b/pkg/apiclient/docs/RunnerMetadata.md new file mode 100644 index 0000000000..645d6f01df --- /dev/null +++ b/pkg/apiclient/docs/RunnerMetadata.md @@ -0,0 +1,140 @@ +# RunnerMetadata + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Providers** | [**[]ProviderInfo**](ProviderInfo.md) | | +**RunnerId** | **string** | | +**RunningJobs** | Pointer to **int32** | | [optional] +**UpdatedAt** | **string** | | +**Uptime** | **int32** | | + +## Methods + +### NewRunnerMetadata + +`func NewRunnerMetadata(providers []ProviderInfo, runnerId string, updatedAt string, uptime int32, ) *RunnerMetadata` + +NewRunnerMetadata instantiates a new RunnerMetadata object +This constructor will assign default values to properties that have it defined, +and makes sure properties required by API are set, but the set of arguments +will change when the set of required properties is changed + +### NewRunnerMetadataWithDefaults + +`func NewRunnerMetadataWithDefaults() *RunnerMetadata` + +NewRunnerMetadataWithDefaults instantiates a new RunnerMetadata object +This constructor will only assign default values to properties that have it defined, +but it doesn't guarantee that properties required by API are set + +### GetProviders + +`func (o *RunnerMetadata) GetProviders() []ProviderInfo` + +GetProviders returns the Providers field if non-nil, zero value otherwise. + +### GetProvidersOk + +`func (o *RunnerMetadata) GetProvidersOk() (*[]ProviderInfo, bool)` + +GetProvidersOk returns a tuple with the Providers field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetProviders + +`func (o *RunnerMetadata) SetProviders(v []ProviderInfo)` + +SetProviders sets Providers field to given value. + + +### GetRunnerId + +`func (o *RunnerMetadata) GetRunnerId() string` + +GetRunnerId returns the RunnerId field if non-nil, zero value otherwise. + +### GetRunnerIdOk + +`func (o *RunnerMetadata) GetRunnerIdOk() (*string, bool)` + +GetRunnerIdOk returns a tuple with the RunnerId field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetRunnerId + +`func (o *RunnerMetadata) SetRunnerId(v string)` + +SetRunnerId sets RunnerId field to given value. + + +### GetRunningJobs + +`func (o *RunnerMetadata) GetRunningJobs() int32` + +GetRunningJobs returns the RunningJobs field if non-nil, zero value otherwise. + +### GetRunningJobsOk + +`func (o *RunnerMetadata) GetRunningJobsOk() (*int32, bool)` + +GetRunningJobsOk returns a tuple with the RunningJobs field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetRunningJobs + +`func (o *RunnerMetadata) SetRunningJobs(v int32)` + +SetRunningJobs sets RunningJobs field to given value. + +### HasRunningJobs + +`func (o *RunnerMetadata) HasRunningJobs() bool` + +HasRunningJobs returns a boolean if a field has been set. + +### GetUpdatedAt + +`func (o *RunnerMetadata) GetUpdatedAt() string` + +GetUpdatedAt returns the UpdatedAt field if non-nil, zero value otherwise. + +### GetUpdatedAtOk + +`func (o *RunnerMetadata) GetUpdatedAtOk() (*string, bool)` + +GetUpdatedAtOk returns a tuple with the UpdatedAt field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetUpdatedAt + +`func (o *RunnerMetadata) SetUpdatedAt(v string)` + +SetUpdatedAt sets UpdatedAt field to given value. + + +### GetUptime + +`func (o *RunnerMetadata) GetUptime() int32` + +GetUptime returns the Uptime field if non-nil, zero value otherwise. + +### GetUptimeOk + +`func (o *RunnerMetadata) GetUptimeOk() (*int32, bool)` + +GetUptimeOk returns a tuple with the Uptime field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetUptime + +`func (o *RunnerMetadata) SetUptime(v int32)` + +SetUptime sets Uptime field to given value. + + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/pkg/apiclient/docs/ServerAPI.md b/pkg/apiclient/docs/ServerAPI.md index 38b0b61ac6..8afbef701e 100644 --- a/pkg/apiclient/docs/ServerAPI.md +++ b/pkg/apiclient/docs/ServerAPI.md @@ -4,18 +4,18 @@ All URIs are relative to *http://localhost:3986* Method | HTTP request | Description ------------- | ------------- | ------------- -[**GenerateNetworkKey**](ServerAPI.md#GenerateNetworkKey) | **Post** /server/network-key | Generate a new authentication key +[**CreateNetworkKey**](ServerAPI.md#CreateNetworkKey) | **Post** /server/network-key | Create a new authentication key [**GetConfig**](ServerAPI.md#GetConfig) | **Get** /server/config | Get the server configuration -[**GetServerLogFiles**](ServerAPI.md#GetServerLogFiles) | **Get** /server/logs | List server log files -[**SetConfig**](ServerAPI.md#SetConfig) | **Post** /server/config | Set the server configuration +[**GetServerLogFiles**](ServerAPI.md#GetServerLogFiles) | **Get** /server/logs | Get server log files +[**SaveConfig**](ServerAPI.md#SaveConfig) | **Put** /server/config | Save the server configuration -## GenerateNetworkKey +## CreateNetworkKey -> NetworkKey GenerateNetworkKey(ctx).Execute() +> NetworkKey CreateNetworkKey(ctx).Execute() -Generate a new authentication key +Create a new authentication key @@ -35,13 +35,13 @@ func main() { configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.ServerAPI.GenerateNetworkKey(context.Background()).Execute() + resp, r, err := apiClient.ServerAPI.CreateNetworkKey(context.Background()).Execute() if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `ServerAPI.GenerateNetworkKey``: %v\n", err) + fmt.Fprintf(os.Stderr, "Error when calling `ServerAPI.CreateNetworkKey``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) } - // response from `GenerateNetworkKey`: NetworkKey - fmt.Fprintf(os.Stdout, "Response from `ServerAPI.GenerateNetworkKey`: %v\n", resp) + // response from `CreateNetworkKey`: NetworkKey + fmt.Fprintf(os.Stdout, "Response from `ServerAPI.CreateNetworkKey`: %v\n", resp) } ``` @@ -51,7 +51,7 @@ This endpoint does not need any parameter. ### Other Parameters -Other parameters are passed through a pointer to a apiGenerateNetworkKeyRequest struct via the builder pattern +Other parameters are passed through a pointer to a apiCreateNetworkKeyRequest struct via the builder pattern ### Return type @@ -137,7 +137,7 @@ Other parameters are passed through a pointer to a apiGetConfigRequest struct vi > []string GetServerLogFiles(ctx).Execute() -List server log files +Get server log files @@ -194,11 +194,11 @@ Other parameters are passed through a pointer to a apiGetServerLogFilesRequest s [[Back to README]](../README.md) -## SetConfig +## SaveConfig -> ServerConfig SetConfig(ctx).Config(config).Execute() +> ServerConfig SaveConfig(ctx).Config(config).Execute() -Set the server configuration +Save the server configuration @@ -215,17 +215,17 @@ import ( ) func main() { - config := *openapiclient.NewServerConfig(int32(123), "BinariesPath_example", "BuilderImage_example", "BuilderRegistryServer_example", "DefaultProjectImage_example", "DefaultProjectUser_example", int32(123), "Id_example", "LocalBuilderRegistryImage_example", int32(123), *openapiclient.NewLogFileConfig(int32(123), int32(123), int32(123), "Path_example"), "ProvidersDir_example", "RegistryUrl_example", "ServerDownloadUrl_example") // ServerConfig | Server configuration + config := *openapiclient.NewServerConfig(int32(123), "BinariesPath_example", "BuilderImage_example", "BuilderRegistryServer_example", "DefaultWorkspaceImage_example", "DefaultWorkspaceUser_example", int32(123), "Id_example", "LocalBuilderRegistryImage_example", int32(123), *openapiclient.NewLogFileConfig(int32(123), int32(123), int32(123), "Path_example"), "RegistryUrl_example", "ServerDownloadUrl_example") // ServerConfig | Server configuration configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.ServerAPI.SetConfig(context.Background()).Config(config).Execute() + resp, r, err := apiClient.ServerAPI.SaveConfig(context.Background()).Config(config).Execute() if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `ServerAPI.SetConfig``: %v\n", err) + fmt.Fprintf(os.Stderr, "Error when calling `ServerAPI.SaveConfig``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) } - // response from `SetConfig`: ServerConfig - fmt.Fprintf(os.Stdout, "Response from `ServerAPI.SetConfig`: %v\n", resp) + // response from `SaveConfig`: ServerConfig + fmt.Fprintf(os.Stdout, "Response from `ServerAPI.SaveConfig`: %v\n", resp) } ``` @@ -235,7 +235,7 @@ func main() { ### Other Parameters -Other parameters are passed through a pointer to a apiSetConfigRequest struct via the builder pattern +Other parameters are passed through a pointer to a apiSaveConfigRequest struct via the builder pattern Name | Type | Description | Notes diff --git a/pkg/apiclient/docs/ServerConfig.md b/pkg/apiclient/docs/ServerConfig.md index 3288de7691..2bb5baaa29 100644 --- a/pkg/apiclient/docs/ServerConfig.md +++ b/pkg/apiclient/docs/ServerConfig.md @@ -9,15 +9,15 @@ Name | Type | Description | Notes **BuildImageNamespace** | Pointer to **string** | | [optional] **BuilderImage** | **string** | | **BuilderRegistryServer** | **string** | | -**DefaultProjectImage** | **string** | | -**DefaultProjectUser** | **string** | | +**DefaultWorkspaceImage** | **string** | | +**DefaultWorkspaceUser** | **string** | | **Frps** | Pointer to [**FRPSConfig**](FRPSConfig.md) | | [optional] **HeadscalePort** | **int32** | | **Id** | **string** | | **LocalBuilderRegistryImage** | **string** | | **LocalBuilderRegistryPort** | **int32** | | +**LocalRunnerDisabled** | Pointer to **bool** | | [optional] **LogFile** | [**LogFileConfig**](LogFileConfig.md) | | -**ProvidersDir** | **string** | | **RegistryUrl** | **string** | | **SamplesIndexUrl** | Pointer to **string** | | [optional] **ServerDownloadUrl** | **string** | | @@ -26,7 +26,7 @@ Name | Type | Description | Notes ### NewServerConfig -`func NewServerConfig(apiPort int32, binariesPath string, builderImage string, builderRegistryServer string, defaultProjectImage string, defaultProjectUser string, headscalePort int32, id string, localBuilderRegistryImage string, localBuilderRegistryPort int32, logFile LogFileConfig, providersDir string, registryUrl string, serverDownloadUrl string, ) *ServerConfig` +`func NewServerConfig(apiPort int32, binariesPath string, builderImage string, builderRegistryServer string, defaultWorkspaceImage string, defaultWorkspaceUser string, headscalePort int32, id string, localBuilderRegistryImage string, localBuilderRegistryPort int32, logFile LogFileConfig, registryUrl string, serverDownloadUrl string, ) *ServerConfig` NewServerConfig instantiates a new ServerConfig object This constructor will assign default values to properties that have it defined, @@ -146,44 +146,44 @@ and a boolean to check if the value has been set. SetBuilderRegistryServer sets BuilderRegistryServer field to given value. -### GetDefaultProjectImage +### GetDefaultWorkspaceImage -`func (o *ServerConfig) GetDefaultProjectImage() string` +`func (o *ServerConfig) GetDefaultWorkspaceImage() string` -GetDefaultProjectImage returns the DefaultProjectImage field if non-nil, zero value otherwise. +GetDefaultWorkspaceImage returns the DefaultWorkspaceImage field if non-nil, zero value otherwise. -### GetDefaultProjectImageOk +### GetDefaultWorkspaceImageOk -`func (o *ServerConfig) GetDefaultProjectImageOk() (*string, bool)` +`func (o *ServerConfig) GetDefaultWorkspaceImageOk() (*string, bool)` -GetDefaultProjectImageOk returns a tuple with the DefaultProjectImage field if it's non-nil, zero value otherwise +GetDefaultWorkspaceImageOk returns a tuple with the DefaultWorkspaceImage field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. -### SetDefaultProjectImage +### SetDefaultWorkspaceImage -`func (o *ServerConfig) SetDefaultProjectImage(v string)` +`func (o *ServerConfig) SetDefaultWorkspaceImage(v string)` -SetDefaultProjectImage sets DefaultProjectImage field to given value. +SetDefaultWorkspaceImage sets DefaultWorkspaceImage field to given value. -### GetDefaultProjectUser +### GetDefaultWorkspaceUser -`func (o *ServerConfig) GetDefaultProjectUser() string` +`func (o *ServerConfig) GetDefaultWorkspaceUser() string` -GetDefaultProjectUser returns the DefaultProjectUser field if non-nil, zero value otherwise. +GetDefaultWorkspaceUser returns the DefaultWorkspaceUser field if non-nil, zero value otherwise. -### GetDefaultProjectUserOk +### GetDefaultWorkspaceUserOk -`func (o *ServerConfig) GetDefaultProjectUserOk() (*string, bool)` +`func (o *ServerConfig) GetDefaultWorkspaceUserOk() (*string, bool)` -GetDefaultProjectUserOk returns a tuple with the DefaultProjectUser field if it's non-nil, zero value otherwise +GetDefaultWorkspaceUserOk returns a tuple with the DefaultWorkspaceUser field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. -### SetDefaultProjectUser +### SetDefaultWorkspaceUser -`func (o *ServerConfig) SetDefaultProjectUser(v string)` +`func (o *ServerConfig) SetDefaultWorkspaceUser(v string)` -SetDefaultProjectUser sets DefaultProjectUser field to given value. +SetDefaultWorkspaceUser sets DefaultWorkspaceUser field to given value. ### GetFrps @@ -291,44 +291,49 @@ and a boolean to check if the value has been set. SetLocalBuilderRegistryPort sets LocalBuilderRegistryPort field to given value. -### GetLogFile +### GetLocalRunnerDisabled -`func (o *ServerConfig) GetLogFile() LogFileConfig` +`func (o *ServerConfig) GetLocalRunnerDisabled() bool` -GetLogFile returns the LogFile field if non-nil, zero value otherwise. +GetLocalRunnerDisabled returns the LocalRunnerDisabled field if non-nil, zero value otherwise. -### GetLogFileOk +### GetLocalRunnerDisabledOk -`func (o *ServerConfig) GetLogFileOk() (*LogFileConfig, bool)` +`func (o *ServerConfig) GetLocalRunnerDisabledOk() (*bool, bool)` -GetLogFileOk returns a tuple with the LogFile field if it's non-nil, zero value otherwise +GetLocalRunnerDisabledOk returns a tuple with the LocalRunnerDisabled field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. -### SetLogFile +### SetLocalRunnerDisabled -`func (o *ServerConfig) SetLogFile(v LogFileConfig)` +`func (o *ServerConfig) SetLocalRunnerDisabled(v bool)` -SetLogFile sets LogFile field to given value. +SetLocalRunnerDisabled sets LocalRunnerDisabled field to given value. + +### HasLocalRunnerDisabled +`func (o *ServerConfig) HasLocalRunnerDisabled() bool` -### GetProvidersDir +HasLocalRunnerDisabled returns a boolean if a field has been set. -`func (o *ServerConfig) GetProvidersDir() string` +### GetLogFile -GetProvidersDir returns the ProvidersDir field if non-nil, zero value otherwise. +`func (o *ServerConfig) GetLogFile() LogFileConfig` -### GetProvidersDirOk +GetLogFile returns the LogFile field if non-nil, zero value otherwise. + +### GetLogFileOk -`func (o *ServerConfig) GetProvidersDirOk() (*string, bool)` +`func (o *ServerConfig) GetLogFileOk() (*LogFileConfig, bool)` -GetProvidersDirOk returns a tuple with the ProvidersDir field if it's non-nil, zero value otherwise +GetLogFileOk returns a tuple with the LogFile field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. -### SetProvidersDir +### SetLogFile -`func (o *ServerConfig) SetProvidersDir(v string)` +`func (o *ServerConfig) SetLogFile(v LogFileConfig)` -SetProvidersDir sets ProvidersDir field to given value. +SetLogFile sets LogFile field to given value. ### GetRegistryUrl diff --git a/pkg/apiclient/docs/Target.md b/pkg/apiclient/docs/Target.md new file mode 100644 index 0000000000..0dac5254c4 --- /dev/null +++ b/pkg/apiclient/docs/Target.md @@ -0,0 +1,281 @@ +# Target + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Default** | **bool** | | +**EnvVars** | **map[string]string** | | +**Id** | **string** | | +**LastJob** | Pointer to [**Job**](Job.md) | | [optional] +**LastJobId** | Pointer to **string** | | [optional] +**Metadata** | Pointer to [**TargetMetadata**](TargetMetadata.md) | | [optional] +**Name** | **string** | | +**ProviderMetadata** | Pointer to **string** | | [optional] +**TargetConfig** | [**TargetConfig**](TargetConfig.md) | | +**TargetConfigId** | **string** | | +**Workspaces** | [**[]Workspace**](Workspace.md) | | + +## Methods + +### NewTarget + +`func NewTarget(default_ bool, envVars map[string]string, id string, name string, targetConfig TargetConfig, targetConfigId string, workspaces []Workspace, ) *Target` + +NewTarget instantiates a new Target object +This constructor will assign default values to properties that have it defined, +and makes sure properties required by API are set, but the set of arguments +will change when the set of required properties is changed + +### NewTargetWithDefaults + +`func NewTargetWithDefaults() *Target` + +NewTargetWithDefaults instantiates a new Target object +This constructor will only assign default values to properties that have it defined, +but it doesn't guarantee that properties required by API are set + +### GetDefault + +`func (o *Target) GetDefault() bool` + +GetDefault returns the Default field if non-nil, zero value otherwise. + +### GetDefaultOk + +`func (o *Target) GetDefaultOk() (*bool, bool)` + +GetDefaultOk returns a tuple with the Default field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetDefault + +`func (o *Target) SetDefault(v bool)` + +SetDefault sets Default field to given value. + + +### GetEnvVars + +`func (o *Target) GetEnvVars() map[string]string` + +GetEnvVars returns the EnvVars field if non-nil, zero value otherwise. + +### GetEnvVarsOk + +`func (o *Target) GetEnvVarsOk() (*map[string]string, bool)` + +GetEnvVarsOk returns a tuple with the EnvVars field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetEnvVars + +`func (o *Target) SetEnvVars(v map[string]string)` + +SetEnvVars sets EnvVars field to given value. + + +### GetId + +`func (o *Target) GetId() string` + +GetId returns the Id field if non-nil, zero value otherwise. + +### GetIdOk + +`func (o *Target) GetIdOk() (*string, bool)` + +GetIdOk returns a tuple with the Id field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetId + +`func (o *Target) SetId(v string)` + +SetId sets Id field to given value. + + +### GetLastJob + +`func (o *Target) GetLastJob() Job` + +GetLastJob returns the LastJob field if non-nil, zero value otherwise. + +### GetLastJobOk + +`func (o *Target) GetLastJobOk() (*Job, bool)` + +GetLastJobOk returns a tuple with the LastJob field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetLastJob + +`func (o *Target) SetLastJob(v Job)` + +SetLastJob sets LastJob field to given value. + +### HasLastJob + +`func (o *Target) HasLastJob() bool` + +HasLastJob returns a boolean if a field has been set. + +### GetLastJobId + +`func (o *Target) GetLastJobId() string` + +GetLastJobId returns the LastJobId field if non-nil, zero value otherwise. + +### GetLastJobIdOk + +`func (o *Target) GetLastJobIdOk() (*string, bool)` + +GetLastJobIdOk returns a tuple with the LastJobId field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetLastJobId + +`func (o *Target) SetLastJobId(v string)` + +SetLastJobId sets LastJobId field to given value. + +### HasLastJobId + +`func (o *Target) HasLastJobId() bool` + +HasLastJobId returns a boolean if a field has been set. + +### GetMetadata + +`func (o *Target) GetMetadata() TargetMetadata` + +GetMetadata returns the Metadata field if non-nil, zero value otherwise. + +### GetMetadataOk + +`func (o *Target) GetMetadataOk() (*TargetMetadata, bool)` + +GetMetadataOk returns a tuple with the Metadata field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetMetadata + +`func (o *Target) SetMetadata(v TargetMetadata)` + +SetMetadata sets Metadata field to given value. + +### HasMetadata + +`func (o *Target) HasMetadata() bool` + +HasMetadata returns a boolean if a field has been set. + +### GetName + +`func (o *Target) GetName() string` + +GetName returns the Name field if non-nil, zero value otherwise. + +### GetNameOk + +`func (o *Target) GetNameOk() (*string, bool)` + +GetNameOk returns a tuple with the Name field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetName + +`func (o *Target) SetName(v string)` + +SetName sets Name field to given value. + + +### GetProviderMetadata + +`func (o *Target) GetProviderMetadata() string` + +GetProviderMetadata returns the ProviderMetadata field if non-nil, zero value otherwise. + +### GetProviderMetadataOk + +`func (o *Target) GetProviderMetadataOk() (*string, bool)` + +GetProviderMetadataOk returns a tuple with the ProviderMetadata field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetProviderMetadata + +`func (o *Target) SetProviderMetadata(v string)` + +SetProviderMetadata sets ProviderMetadata field to given value. + +### HasProviderMetadata + +`func (o *Target) HasProviderMetadata() bool` + +HasProviderMetadata returns a boolean if a field has been set. + +### GetTargetConfig + +`func (o *Target) GetTargetConfig() TargetConfig` + +GetTargetConfig returns the TargetConfig field if non-nil, zero value otherwise. + +### GetTargetConfigOk + +`func (o *Target) GetTargetConfigOk() (*TargetConfig, bool)` + +GetTargetConfigOk returns a tuple with the TargetConfig field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetTargetConfig + +`func (o *Target) SetTargetConfig(v TargetConfig)` + +SetTargetConfig sets TargetConfig field to given value. + + +### GetTargetConfigId + +`func (o *Target) GetTargetConfigId() string` + +GetTargetConfigId returns the TargetConfigId field if non-nil, zero value otherwise. + +### GetTargetConfigIdOk + +`func (o *Target) GetTargetConfigIdOk() (*string, bool)` + +GetTargetConfigIdOk returns a tuple with the TargetConfigId field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetTargetConfigId + +`func (o *Target) SetTargetConfigId(v string)` + +SetTargetConfigId sets TargetConfigId field to given value. + + +### GetWorkspaces + +`func (o *Target) GetWorkspaces() []Workspace` + +GetWorkspaces returns the Workspaces field if non-nil, zero value otherwise. + +### GetWorkspacesOk + +`func (o *Target) GetWorkspacesOk() (*[]Workspace, bool)` + +GetWorkspacesOk returns a tuple with the Workspaces field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetWorkspaces + +`func (o *Target) SetWorkspaces(v []Workspace)` + +SetWorkspaces sets Workspaces field to given value. + + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/pkg/apiclient/docs/TargetAPI.md b/pkg/apiclient/docs/TargetAPI.md index d4232dba94..0f9e64b337 100644 --- a/pkg/apiclient/docs/TargetAPI.md +++ b/pkg/apiclient/docs/TargetAPI.md @@ -4,16 +4,370 @@ All URIs are relative to *http://localhost:3986* Method | HTTP request | Description ------------- | ------------- | ------------- +[**CreateTarget**](TargetAPI.md#CreateTarget) | **Post** /target | Create a target +[**DeleteTarget**](TargetAPI.md#DeleteTarget) | **Delete** /target/{targetId} | Delete target +[**FindTarget**](TargetAPI.md#FindTarget) | **Get** /target/{targetId} | Find target +[**GetTargetState**](TargetAPI.md#GetTargetState) | **Get** /target/{targetId}/state | Get target state +[**HandleSuccessfulCreation**](TargetAPI.md#HandleSuccessfulCreation) | **Post** /target/{targetId}/handle-successful-creation | Handles successful creation of the target [**ListTargets**](TargetAPI.md#ListTargets) | **Get** /target | List targets -[**RemoveTarget**](TargetAPI.md#RemoveTarget) | **Delete** /target/{target} | Remove a target -[**SetDefaultTarget**](TargetAPI.md#SetDefaultTarget) | **Patch** /target/{target}/set-default | Set target to default -[**SetTarget**](TargetAPI.md#SetTarget) | **Put** /target | Set a target +[**RestartTarget**](TargetAPI.md#RestartTarget) | **Post** /target/{targetId}/restart | Restart target +[**SetDefaultTarget**](TargetAPI.md#SetDefaultTarget) | **Patch** /target/{targetId}/set-default | Set target to be used by default +[**StartTarget**](TargetAPI.md#StartTarget) | **Post** /target/{targetId}/start | Start target +[**StopTarget**](TargetAPI.md#StopTarget) | **Post** /target/{targetId}/stop | Stop target +[**UpdateTargetMetadata**](TargetAPI.md#UpdateTargetMetadata) | **Post** /target/{targetId}/metadata | Update target metadata +[**UpdateTargetProviderMetadata**](TargetAPI.md#UpdateTargetProviderMetadata) | **Post** /target/{targetId}/provider-metadata | Update target provider metadata +## CreateTarget + +> Target CreateTarget(ctx).Target(target).Execute() + +Create a target + + + +### Example + +```go +package main + +import ( + "context" + "fmt" + "os" + openapiclient "github.com/GIT_USER_ID/GIT_REPO_ID/apiclient" +) + +func main() { + target := *openapiclient.NewCreateTargetDTO("Id_example", "Name_example", "TargetConfigId_example") // CreateTargetDTO | Create target + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.TargetAPI.CreateTarget(context.Background()).Target(target).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `TargetAPI.CreateTarget``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `CreateTarget`: Target + fmt.Fprintf(os.Stdout, "Response from `TargetAPI.CreateTarget`: %v\n", resp) +} +``` + +### Path Parameters + + + +### Other Parameters + +Other parameters are passed through a pointer to a apiCreateTargetRequest struct via the builder pattern + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **target** | [**CreateTargetDTO**](CreateTargetDTO.md) | Create target | + +### Return type + +[**Target**](Target.md) + +### Authorization + +[Bearer](../README.md#Bearer) + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) +[[Back to Model list]](../README.md#documentation-for-models) +[[Back to README]](../README.md) + + +## DeleteTarget + +> DeleteTarget(ctx, targetId).Force(force).Execute() + +Delete target + + + +### Example + +```go +package main + +import ( + "context" + "fmt" + "os" + openapiclient "github.com/GIT_USER_ID/GIT_REPO_ID/apiclient" +) + +func main() { + targetId := "targetId_example" // string | Target ID + force := true // bool | Force (optional) + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + r, err := apiClient.TargetAPI.DeleteTarget(context.Background(), targetId).Force(force).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `TargetAPI.DeleteTarget``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } +} +``` + +### Path Parameters + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- +**ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. +**targetId** | **string** | Target ID | + +### Other Parameters + +Other parameters are passed through a pointer to a apiDeleteTargetRequest struct via the builder pattern + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + + **force** | **bool** | Force | + +### Return type + + (empty response body) + +### Authorization + +[Bearer](../README.md#Bearer) + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: Not defined + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) +[[Back to Model list]](../README.md#documentation-for-models) +[[Back to README]](../README.md) + + +## FindTarget + +> TargetDTO FindTarget(ctx, targetId).ShowOptions(showOptions).Execute() + +Find target + + + +### Example + +```go +package main + +import ( + "context" + "fmt" + "os" + openapiclient "github.com/GIT_USER_ID/GIT_REPO_ID/apiclient" +) + +func main() { + targetId := "targetId_example" // string | Target ID or Name + showOptions := true // bool | Show target config options (optional) + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.TargetAPI.FindTarget(context.Background(), targetId).ShowOptions(showOptions).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `TargetAPI.FindTarget``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `FindTarget`: TargetDTO + fmt.Fprintf(os.Stdout, "Response from `TargetAPI.FindTarget`: %v\n", resp) +} +``` + +### Path Parameters + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- +**ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. +**targetId** | **string** | Target ID or Name | + +### Other Parameters + +Other parameters are passed through a pointer to a apiFindTargetRequest struct via the builder pattern + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + + **showOptions** | **bool** | Show target config options | + +### Return type + +[**TargetDTO**](TargetDTO.md) + +### Authorization + +[Bearer](../README.md#Bearer) + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) +[[Back to Model list]](../README.md#documentation-for-models) +[[Back to README]](../README.md) + + +## GetTargetState + +> ResourceState GetTargetState(ctx, targetId).Execute() + +Get target state + + + +### Example + +```go +package main + +import ( + "context" + "fmt" + "os" + openapiclient "github.com/GIT_USER_ID/GIT_REPO_ID/apiclient" +) + +func main() { + targetId := "targetId_example" // string | Target ID or Name + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.TargetAPI.GetTargetState(context.Background(), targetId).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `TargetAPI.GetTargetState``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `GetTargetState`: ResourceState + fmt.Fprintf(os.Stdout, "Response from `TargetAPI.GetTargetState`: %v\n", resp) +} +``` + +### Path Parameters + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- +**ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. +**targetId** | **string** | Target ID or Name | + +### Other Parameters + +Other parameters are passed through a pointer to a apiGetTargetStateRequest struct via the builder pattern + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + + +### Return type + +[**ResourceState**](ResourceState.md) + +### Authorization + +[Bearer](../README.md#Bearer) + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) +[[Back to Model list]](../README.md#documentation-for-models) +[[Back to README]](../README.md) + + +## HandleSuccessfulCreation + +> HandleSuccessfulCreation(ctx, targetId).Execute() + +Handles successful creation of the target + + + +### Example + +```go +package main + +import ( + "context" + "fmt" + "os" + openapiclient "github.com/GIT_USER_ID/GIT_REPO_ID/apiclient" +) + +func main() { + targetId := "targetId_example" // string | Target ID or name + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + r, err := apiClient.TargetAPI.HandleSuccessfulCreation(context.Background(), targetId).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `TargetAPI.HandleSuccessfulCreation``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } +} +``` + +### Path Parameters + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- +**ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. +**targetId** | **string** | Target ID or name | + +### Other Parameters + +Other parameters are passed through a pointer to a apiHandleSuccessfulCreationRequest struct via the builder pattern + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + + +### Return type + + (empty response body) + +### Authorization + +[Bearer](../README.md#Bearer) + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: Not defined + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) +[[Back to Model list]](../README.md#documentation-for-models) +[[Back to README]](../README.md) + + ## ListTargets -> []ProviderTarget ListTargets(ctx).Execute() +> []TargetDTO ListTargets(ctx).ShowOptions(showOptions).Execute() List targets @@ -32,31 +386,36 @@ import ( ) func main() { + showOptions := true // bool | Show target config options (optional) configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.TargetAPI.ListTargets(context.Background()).Execute() + resp, r, err := apiClient.TargetAPI.ListTargets(context.Background()).ShowOptions(showOptions).Execute() if err != nil { fmt.Fprintf(os.Stderr, "Error when calling `TargetAPI.ListTargets``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) } - // response from `ListTargets`: []ProviderTarget + // response from `ListTargets`: []TargetDTO fmt.Fprintf(os.Stdout, "Response from `TargetAPI.ListTargets`: %v\n", resp) } ``` ### Path Parameters -This endpoint does not need any parameter. + ### Other Parameters Other parameters are passed through a pointer to a apiListTargetsRequest struct via the builder pattern +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **showOptions** | **bool** | Show target config options | + ### Return type -[**[]ProviderTarget**](ProviderTarget.md) +[**[]TargetDTO**](TargetDTO.md) ### Authorization @@ -72,11 +431,11 @@ Other parameters are passed through a pointer to a apiListTargetsRequest struct [[Back to README]](../README.md) -## RemoveTarget +## RestartTarget -> RemoveTarget(ctx, target).Execute() +> RestartTarget(ctx, targetId).Execute() -Remove a target +Restart target @@ -93,13 +452,13 @@ import ( ) func main() { - target := "target_example" // string | Target name + targetId := "targetId_example" // string | Target ID or Name configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - r, err := apiClient.TargetAPI.RemoveTarget(context.Background(), target).Execute() + r, err := apiClient.TargetAPI.RestartTarget(context.Background(), targetId).Execute() if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `TargetAPI.RemoveTarget``: %v\n", err) + fmt.Fprintf(os.Stderr, "Error when calling `TargetAPI.RestartTarget``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) } } @@ -111,11 +470,11 @@ func main() { Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. -**target** | **string** | Target name | +**targetId** | **string** | Target ID or Name | ### Other Parameters -Other parameters are passed through a pointer to a apiRemoveTargetRequest struct via the builder pattern +Other parameters are passed through a pointer to a apiRestartTargetRequest struct via the builder pattern Name | Type | Description | Notes @@ -142,9 +501,9 @@ Name | Type | Description | Notes ## SetDefaultTarget -> SetDefaultTarget(ctx, target).Execute() +> SetDefaultTarget(ctx, targetId).Execute() -Set target to default +Set target to be used by default @@ -161,11 +520,11 @@ import ( ) func main() { - target := "target_example" // string | Target name + targetId := "targetId_example" // string | Target ID or name configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - r, err := apiClient.TargetAPI.SetDefaultTarget(context.Background(), target).Execute() + r, err := apiClient.TargetAPI.SetDefaultTarget(context.Background(), targetId).Execute() if err != nil { fmt.Fprintf(os.Stderr, "Error when calling `TargetAPI.SetDefaultTarget``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) @@ -179,7 +538,7 @@ func main() { Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. -**target** | **string** | Target name | +**targetId** | **string** | Target ID or name | ### Other Parameters @@ -208,11 +567,217 @@ Name | Type | Description | Notes [[Back to README]](../README.md) -## SetTarget +## StartTarget + +> StartTarget(ctx, targetId).Execute() + +Start target + + + +### Example + +```go +package main + +import ( + "context" + "fmt" + "os" + openapiclient "github.com/GIT_USER_ID/GIT_REPO_ID/apiclient" +) + +func main() { + targetId := "targetId_example" // string | Target ID or Name + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + r, err := apiClient.TargetAPI.StartTarget(context.Background(), targetId).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `TargetAPI.StartTarget``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } +} +``` + +### Path Parameters + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- +**ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. +**targetId** | **string** | Target ID or Name | + +### Other Parameters + +Other parameters are passed through a pointer to a apiStartTargetRequest struct via the builder pattern + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + + +### Return type + + (empty response body) + +### Authorization + +[Bearer](../README.md#Bearer) + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: Not defined + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) +[[Back to Model list]](../README.md#documentation-for-models) +[[Back to README]](../README.md) + + +## StopTarget + +> StopTarget(ctx, targetId).Execute() + +Stop target + + + +### Example + +```go +package main + +import ( + "context" + "fmt" + "os" + openapiclient "github.com/GIT_USER_ID/GIT_REPO_ID/apiclient" +) + +func main() { + targetId := "targetId_example" // string | Target ID or Name + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + r, err := apiClient.TargetAPI.StopTarget(context.Background(), targetId).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `TargetAPI.StopTarget``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } +} +``` + +### Path Parameters + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- +**ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. +**targetId** | **string** | Target ID or Name | + +### Other Parameters + +Other parameters are passed through a pointer to a apiStopTargetRequest struct via the builder pattern + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + + +### Return type + + (empty response body) + +### Authorization + +[Bearer](../README.md#Bearer) + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: Not defined + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) +[[Back to Model list]](../README.md#documentation-for-models) +[[Back to README]](../README.md) + + +## UpdateTargetMetadata + +> UpdateTargetMetadata(ctx, targetId).TargetMetadata(targetMetadata).Execute() + +Update target metadata + + + +### Example + +```go +package main + +import ( + "context" + "fmt" + "os" + openapiclient "github.com/GIT_USER_ID/GIT_REPO_ID/apiclient" +) + +func main() { + targetId := "targetId_example" // string | Target ID + targetMetadata := *openapiclient.NewUpdateTargetMetadataDTO(int32(123)) // UpdateTargetMetadataDTO | Target Metadata + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + r, err := apiClient.TargetAPI.UpdateTargetMetadata(context.Background(), targetId).TargetMetadata(targetMetadata).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `TargetAPI.UpdateTargetMetadata``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } +} +``` + +### Path Parameters + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- +**ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. +**targetId** | **string** | Target ID | + +### Other Parameters + +Other parameters are passed through a pointer to a apiUpdateTargetMetadataRequest struct via the builder pattern + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + + **targetMetadata** | [**UpdateTargetMetadataDTO**](UpdateTargetMetadataDTO.md) | Target Metadata | + +### Return type + + (empty response body) + +### Authorization + +[Bearer](../README.md#Bearer) + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: Not defined + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) +[[Back to Model list]](../README.md#documentation-for-models) +[[Back to README]](../README.md) + + +## UpdateTargetProviderMetadata -> SetTarget(ctx).Target(target).Execute() +> UpdateTargetProviderMetadata(ctx, targetId).Metadata(metadata).Execute() -Set a target +Update target provider metadata @@ -229,13 +794,14 @@ import ( ) func main() { - target := *openapiclient.NewCreateProviderTargetDTO("Name_example", "Options_example", *openapiclient.NewProviderProviderInfo("Name_example", "Version_example")) // CreateProviderTargetDTO | Target to set + targetId := "targetId_example" // string | Target ID + metadata := *openapiclient.NewUpdateTargetProviderMetadataDTO("Metadata_example") // UpdateTargetProviderMetadataDTO | Provider metadata configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - r, err := apiClient.TargetAPI.SetTarget(context.Background()).Target(target).Execute() + r, err := apiClient.TargetAPI.UpdateTargetProviderMetadata(context.Background(), targetId).Metadata(metadata).Execute() if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `TargetAPI.SetTarget``: %v\n", err) + fmt.Fprintf(os.Stderr, "Error when calling `TargetAPI.UpdateTargetProviderMetadata``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) } } @@ -244,15 +810,20 @@ func main() { ### Path Parameters +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- +**ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. +**targetId** | **string** | Target ID | ### Other Parameters -Other parameters are passed through a pointer to a apiSetTargetRequest struct via the builder pattern +Other parameters are passed through a pointer to a apiUpdateTargetProviderMetadataRequest struct via the builder pattern Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - **target** | [**CreateProviderTargetDTO**](CreateProviderTargetDTO.md) | Target to set | + + **metadata** | [**UpdateTargetProviderMetadataDTO**](UpdateTargetProviderMetadataDTO.md) | Provider metadata | ### Return type diff --git a/pkg/apiclient/docs/ProviderTarget.md b/pkg/apiclient/docs/TargetConfig.md similarity index 50% rename from pkg/apiclient/docs/ProviderTarget.md rename to pkg/apiclient/docs/TargetConfig.md index e4592a685d..665ffb3061 100644 --- a/pkg/apiclient/docs/ProviderTarget.md +++ b/pkg/apiclient/docs/TargetConfig.md @@ -1,109 +1,130 @@ -# ProviderTarget +# TargetConfig ## Properties Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**IsDefault** | **bool** | | +**Deleted** | **bool** | | +**Id** | **string** | | **Name** | **string** | | **Options** | **string** | JSON encoded map of options | -**ProviderInfo** | [**ProviderProviderInfo**](ProviderProviderInfo.md) | | +**ProviderInfo** | [**ProviderInfo**](ProviderInfo.md) | | ## Methods -### NewProviderTarget +### NewTargetConfig -`func NewProviderTarget(isDefault bool, name string, options string, providerInfo ProviderProviderInfo, ) *ProviderTarget` +`func NewTargetConfig(deleted bool, id string, name string, options string, providerInfo ProviderInfo, ) *TargetConfig` -NewProviderTarget instantiates a new ProviderTarget object +NewTargetConfig instantiates a new TargetConfig object This constructor will assign default values to properties that have it defined, and makes sure properties required by API are set, but the set of arguments will change when the set of required properties is changed -### NewProviderTargetWithDefaults +### NewTargetConfigWithDefaults -`func NewProviderTargetWithDefaults() *ProviderTarget` +`func NewTargetConfigWithDefaults() *TargetConfig` -NewProviderTargetWithDefaults instantiates a new ProviderTarget object +NewTargetConfigWithDefaults instantiates a new TargetConfig object This constructor will only assign default values to properties that have it defined, but it doesn't guarantee that properties required by API are set -### GetIsDefault +### GetDeleted -`func (o *ProviderTarget) GetIsDefault() bool` +`func (o *TargetConfig) GetDeleted() bool` -GetIsDefault returns the IsDefault field if non-nil, zero value otherwise. +GetDeleted returns the Deleted field if non-nil, zero value otherwise. -### GetIsDefaultOk +### GetDeletedOk -`func (o *ProviderTarget) GetIsDefaultOk() (*bool, bool)` +`func (o *TargetConfig) GetDeletedOk() (*bool, bool)` -GetIsDefaultOk returns a tuple with the IsDefault field if it's non-nil, zero value otherwise +GetDeletedOk returns a tuple with the Deleted field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. -### SetIsDefault +### SetDeleted -`func (o *ProviderTarget) SetIsDefault(v bool)` +`func (o *TargetConfig) SetDeleted(v bool)` -SetIsDefault sets IsDefault field to given value. +SetDeleted sets Deleted field to given value. + + +### GetId + +`func (o *TargetConfig) GetId() string` + +GetId returns the Id field if non-nil, zero value otherwise. + +### GetIdOk + +`func (o *TargetConfig) GetIdOk() (*string, bool)` + +GetIdOk returns a tuple with the Id field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetId + +`func (o *TargetConfig) SetId(v string)` + +SetId sets Id field to given value. ### GetName -`func (o *ProviderTarget) GetName() string` +`func (o *TargetConfig) GetName() string` GetName returns the Name field if non-nil, zero value otherwise. ### GetNameOk -`func (o *ProviderTarget) GetNameOk() (*string, bool)` +`func (o *TargetConfig) GetNameOk() (*string, bool)` GetNameOk returns a tuple with the Name field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. ### SetName -`func (o *ProviderTarget) SetName(v string)` +`func (o *TargetConfig) SetName(v string)` SetName sets Name field to given value. ### GetOptions -`func (o *ProviderTarget) GetOptions() string` +`func (o *TargetConfig) GetOptions() string` GetOptions returns the Options field if non-nil, zero value otherwise. ### GetOptionsOk -`func (o *ProviderTarget) GetOptionsOk() (*string, bool)` +`func (o *TargetConfig) GetOptionsOk() (*string, bool)` GetOptionsOk returns a tuple with the Options field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. ### SetOptions -`func (o *ProviderTarget) SetOptions(v string)` +`func (o *TargetConfig) SetOptions(v string)` SetOptions sets Options field to given value. ### GetProviderInfo -`func (o *ProviderTarget) GetProviderInfo() ProviderProviderInfo` +`func (o *TargetConfig) GetProviderInfo() ProviderInfo` GetProviderInfo returns the ProviderInfo field if non-nil, zero value otherwise. ### GetProviderInfoOk -`func (o *ProviderTarget) GetProviderInfoOk() (*ProviderProviderInfo, bool)` +`func (o *TargetConfig) GetProviderInfoOk() (*ProviderInfo, bool)` GetProviderInfoOk returns a tuple with the ProviderInfo field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. ### SetProviderInfo -`func (o *ProviderTarget) SetProviderInfo(v ProviderProviderInfo)` +`func (o *TargetConfig) SetProviderInfo(v ProviderInfo)` SetProviderInfo sets ProviderInfo field to given value. diff --git a/pkg/apiclient/docs/TargetConfigAPI.md b/pkg/apiclient/docs/TargetConfigAPI.md new file mode 100644 index 0000000000..95b660c910 --- /dev/null +++ b/pkg/apiclient/docs/TargetConfigAPI.md @@ -0,0 +1,213 @@ +# \TargetConfigAPI + +All URIs are relative to *http://localhost:3986* + +Method | HTTP request | Description +------------- | ------------- | ------------- +[**CreateTargetConfig**](TargetConfigAPI.md#CreateTargetConfig) | **Post** /target-config | Create a target config +[**DeleteTargetConfig**](TargetConfigAPI.md#DeleteTargetConfig) | **Delete** /target-config/{configId} | Delete a target config +[**ListTargetConfigs**](TargetConfigAPI.md#ListTargetConfigs) | **Get** /target-config | List target configs + + + +## CreateTargetConfig + +> TargetConfig CreateTargetConfig(ctx).TargetConfig(targetConfig).ShowOptions(showOptions).Execute() + +Create a target config + + + +### Example + +```go +package main + +import ( + "context" + "fmt" + "os" + openapiclient "github.com/GIT_USER_ID/GIT_REPO_ID/apiclient" +) + +func main() { + targetConfig := *openapiclient.NewCreateTargetConfigDTO("Name_example", "Options_example", *openapiclient.NewProviderInfo("Name_example", "RunnerId_example", "RunnerName_example", map[string]TargetConfigProperty{"key": *openapiclient.NewTargetConfigProperty()}, "Version_example")) // CreateTargetConfigDTO | Target config to create + showOptions := true // bool | Show target config options (optional) + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.TargetConfigAPI.CreateTargetConfig(context.Background()).TargetConfig(targetConfig).ShowOptions(showOptions).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `TargetConfigAPI.CreateTargetConfig``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `CreateTargetConfig`: TargetConfig + fmt.Fprintf(os.Stdout, "Response from `TargetConfigAPI.CreateTargetConfig`: %v\n", resp) +} +``` + +### Path Parameters + + + +### Other Parameters + +Other parameters are passed through a pointer to a apiCreateTargetConfigRequest struct via the builder pattern + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **targetConfig** | [**CreateTargetConfigDTO**](CreateTargetConfigDTO.md) | Target config to create | + **showOptions** | **bool** | Show target config options | + +### Return type + +[**TargetConfig**](TargetConfig.md) + +### Authorization + +[Bearer](../README.md#Bearer) + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: */* + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) +[[Back to Model list]](../README.md#documentation-for-models) +[[Back to README]](../README.md) + + +## DeleteTargetConfig + +> DeleteTargetConfig(ctx, configId).Execute() + +Delete a target config + + + +### Example + +```go +package main + +import ( + "context" + "fmt" + "os" + openapiclient "github.com/GIT_USER_ID/GIT_REPO_ID/apiclient" +) + +func main() { + configId := "configId_example" // string | Target Config Id + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + r, err := apiClient.TargetConfigAPI.DeleteTargetConfig(context.Background(), configId).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `TargetConfigAPI.DeleteTargetConfig``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } +} +``` + +### Path Parameters + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- +**ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. +**configId** | **string** | Target Config Id | + +### Other Parameters + +Other parameters are passed through a pointer to a apiDeleteTargetConfigRequest struct via the builder pattern + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + + +### Return type + + (empty response body) + +### Authorization + +[Bearer](../README.md#Bearer) + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: Not defined + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) +[[Back to Model list]](../README.md#documentation-for-models) +[[Back to README]](../README.md) + + +## ListTargetConfigs + +> []TargetConfig ListTargetConfigs(ctx).ShowOptions(showOptions).Execute() + +List target configs + + + +### Example + +```go +package main + +import ( + "context" + "fmt" + "os" + openapiclient "github.com/GIT_USER_ID/GIT_REPO_ID/apiclient" +) + +func main() { + showOptions := true // bool | Show target config options (optional) + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.TargetConfigAPI.ListTargetConfigs(context.Background()).ShowOptions(showOptions).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `TargetConfigAPI.ListTargetConfigs``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `ListTargetConfigs`: []TargetConfig + fmt.Fprintf(os.Stdout, "Response from `TargetConfigAPI.ListTargetConfigs`: %v\n", resp) +} +``` + +### Path Parameters + + + +### Other Parameters + +Other parameters are passed through a pointer to a apiListTargetConfigsRequest struct via the builder pattern + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **showOptions** | **bool** | Show target config options | + +### Return type + +[**[]TargetConfig**](TargetConfig.md) + +### Authorization + +[Bearer](../README.md#Bearer) + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) +[[Back to Model list]](../README.md#documentation-for-models) +[[Back to README]](../README.md) + diff --git a/pkg/apiclient/docs/ProviderProviderTargetProperty.md b/pkg/apiclient/docs/TargetConfigProperty.md similarity index 59% rename from pkg/apiclient/docs/ProviderProviderTargetProperty.md rename to pkg/apiclient/docs/TargetConfigProperty.md index cbc47b1dd6..7142de8a44 100644 --- a/pkg/apiclient/docs/ProviderProviderTargetProperty.md +++ b/pkg/apiclient/docs/TargetConfigProperty.md @@ -1,4 +1,4 @@ -# ProviderProviderTargetProperty +# TargetConfigProperty ## Properties @@ -6,203 +6,203 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- **DefaultValue** | Pointer to **string** | DefaultValue is converted into the appropriate type based on the Type If the property is a FilePath, the DefaultValue is a path to a directory | [optional] **Description** | Pointer to **string** | Brief description of the property | [optional] -**DisabledPredicate** | Pointer to **string** | A regex string matched with the name of the target to determine if the property should be disabled If the regex matches the target name, the property will be disabled E.g. \"^local$\" will disable the property for the local target | [optional] +**DisabledPredicate** | Pointer to **string** | A regex string matched with the name of the target config to determine if the property should be disabled If the regex matches the target config name, the property will be disabled E.g. \"^local$\" will disable the property for the local target | [optional] **InputMasked** | Pointer to **bool** | | [optional] -**Options** | Pointer to **[]string** | Options is only used if the Type is ProviderTargetPropertyTypeOption | [optional] +**Options** | Pointer to **[]string** | Options is only used if the Type is TargetConfigPropertyTypeOption | [optional] **Suggestions** | Pointer to **[]string** | Suggestions is an optional list of auto-complete values to assist the user while filling the field | [optional] -**Type** | Pointer to [**ProviderProviderTargetPropertyType**](ProviderProviderTargetPropertyType.md) | | [optional] +**Type** | Pointer to [**ModelsTargetConfigPropertyType**](ModelsTargetConfigPropertyType.md) | | [optional] ## Methods -### NewProviderProviderTargetProperty +### NewTargetConfigProperty -`func NewProviderProviderTargetProperty() *ProviderProviderTargetProperty` +`func NewTargetConfigProperty() *TargetConfigProperty` -NewProviderProviderTargetProperty instantiates a new ProviderProviderTargetProperty object +NewTargetConfigProperty instantiates a new TargetConfigProperty object This constructor will assign default values to properties that have it defined, and makes sure properties required by API are set, but the set of arguments will change when the set of required properties is changed -### NewProviderProviderTargetPropertyWithDefaults +### NewTargetConfigPropertyWithDefaults -`func NewProviderProviderTargetPropertyWithDefaults() *ProviderProviderTargetProperty` +`func NewTargetConfigPropertyWithDefaults() *TargetConfigProperty` -NewProviderProviderTargetPropertyWithDefaults instantiates a new ProviderProviderTargetProperty object +NewTargetConfigPropertyWithDefaults instantiates a new TargetConfigProperty object This constructor will only assign default values to properties that have it defined, but it doesn't guarantee that properties required by API are set ### GetDefaultValue -`func (o *ProviderProviderTargetProperty) GetDefaultValue() string` +`func (o *TargetConfigProperty) GetDefaultValue() string` GetDefaultValue returns the DefaultValue field if non-nil, zero value otherwise. ### GetDefaultValueOk -`func (o *ProviderProviderTargetProperty) GetDefaultValueOk() (*string, bool)` +`func (o *TargetConfigProperty) GetDefaultValueOk() (*string, bool)` GetDefaultValueOk returns a tuple with the DefaultValue field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. ### SetDefaultValue -`func (o *ProviderProviderTargetProperty) SetDefaultValue(v string)` +`func (o *TargetConfigProperty) SetDefaultValue(v string)` SetDefaultValue sets DefaultValue field to given value. ### HasDefaultValue -`func (o *ProviderProviderTargetProperty) HasDefaultValue() bool` +`func (o *TargetConfigProperty) HasDefaultValue() bool` HasDefaultValue returns a boolean if a field has been set. ### GetDescription -`func (o *ProviderProviderTargetProperty) GetDescription() string` +`func (o *TargetConfigProperty) GetDescription() string` GetDescription returns the Description field if non-nil, zero value otherwise. ### GetDescriptionOk -`func (o *ProviderProviderTargetProperty) GetDescriptionOk() (*string, bool)` +`func (o *TargetConfigProperty) GetDescriptionOk() (*string, bool)` GetDescriptionOk returns a tuple with the Description field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. ### SetDescription -`func (o *ProviderProviderTargetProperty) SetDescription(v string)` +`func (o *TargetConfigProperty) SetDescription(v string)` SetDescription sets Description field to given value. ### HasDescription -`func (o *ProviderProviderTargetProperty) HasDescription() bool` +`func (o *TargetConfigProperty) HasDescription() bool` HasDescription returns a boolean if a field has been set. ### GetDisabledPredicate -`func (o *ProviderProviderTargetProperty) GetDisabledPredicate() string` +`func (o *TargetConfigProperty) GetDisabledPredicate() string` GetDisabledPredicate returns the DisabledPredicate field if non-nil, zero value otherwise. ### GetDisabledPredicateOk -`func (o *ProviderProviderTargetProperty) GetDisabledPredicateOk() (*string, bool)` +`func (o *TargetConfigProperty) GetDisabledPredicateOk() (*string, bool)` GetDisabledPredicateOk returns a tuple with the DisabledPredicate field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. ### SetDisabledPredicate -`func (o *ProviderProviderTargetProperty) SetDisabledPredicate(v string)` +`func (o *TargetConfigProperty) SetDisabledPredicate(v string)` SetDisabledPredicate sets DisabledPredicate field to given value. ### HasDisabledPredicate -`func (o *ProviderProviderTargetProperty) HasDisabledPredicate() bool` +`func (o *TargetConfigProperty) HasDisabledPredicate() bool` HasDisabledPredicate returns a boolean if a field has been set. ### GetInputMasked -`func (o *ProviderProviderTargetProperty) GetInputMasked() bool` +`func (o *TargetConfigProperty) GetInputMasked() bool` GetInputMasked returns the InputMasked field if non-nil, zero value otherwise. ### GetInputMaskedOk -`func (o *ProviderProviderTargetProperty) GetInputMaskedOk() (*bool, bool)` +`func (o *TargetConfigProperty) GetInputMaskedOk() (*bool, bool)` GetInputMaskedOk returns a tuple with the InputMasked field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. ### SetInputMasked -`func (o *ProviderProviderTargetProperty) SetInputMasked(v bool)` +`func (o *TargetConfigProperty) SetInputMasked(v bool)` SetInputMasked sets InputMasked field to given value. ### HasInputMasked -`func (o *ProviderProviderTargetProperty) HasInputMasked() bool` +`func (o *TargetConfigProperty) HasInputMasked() bool` HasInputMasked returns a boolean if a field has been set. ### GetOptions -`func (o *ProviderProviderTargetProperty) GetOptions() []string` +`func (o *TargetConfigProperty) GetOptions() []string` GetOptions returns the Options field if non-nil, zero value otherwise. ### GetOptionsOk -`func (o *ProviderProviderTargetProperty) GetOptionsOk() (*[]string, bool)` +`func (o *TargetConfigProperty) GetOptionsOk() (*[]string, bool)` GetOptionsOk returns a tuple with the Options field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. ### SetOptions -`func (o *ProviderProviderTargetProperty) SetOptions(v []string)` +`func (o *TargetConfigProperty) SetOptions(v []string)` SetOptions sets Options field to given value. ### HasOptions -`func (o *ProviderProviderTargetProperty) HasOptions() bool` +`func (o *TargetConfigProperty) HasOptions() bool` HasOptions returns a boolean if a field has been set. ### GetSuggestions -`func (o *ProviderProviderTargetProperty) GetSuggestions() []string` +`func (o *TargetConfigProperty) GetSuggestions() []string` GetSuggestions returns the Suggestions field if non-nil, zero value otherwise. ### GetSuggestionsOk -`func (o *ProviderProviderTargetProperty) GetSuggestionsOk() (*[]string, bool)` +`func (o *TargetConfigProperty) GetSuggestionsOk() (*[]string, bool)` GetSuggestionsOk returns a tuple with the Suggestions field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. ### SetSuggestions -`func (o *ProviderProviderTargetProperty) SetSuggestions(v []string)` +`func (o *TargetConfigProperty) SetSuggestions(v []string)` SetSuggestions sets Suggestions field to given value. ### HasSuggestions -`func (o *ProviderProviderTargetProperty) HasSuggestions() bool` +`func (o *TargetConfigProperty) HasSuggestions() bool` HasSuggestions returns a boolean if a field has been set. ### GetType -`func (o *ProviderProviderTargetProperty) GetType() ProviderProviderTargetPropertyType` +`func (o *TargetConfigProperty) GetType() ModelsTargetConfigPropertyType` GetType returns the Type field if non-nil, zero value otherwise. ### GetTypeOk -`func (o *ProviderProviderTargetProperty) GetTypeOk() (*ProviderProviderTargetPropertyType, bool)` +`func (o *TargetConfigProperty) GetTypeOk() (*ModelsTargetConfigPropertyType, bool)` GetTypeOk returns a tuple with the Type field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. ### SetType -`func (o *ProviderProviderTargetProperty) SetType(v ProviderProviderTargetPropertyType)` +`func (o *TargetConfigProperty) SetType(v ModelsTargetConfigPropertyType)` SetType sets Type field to given value. ### HasType -`func (o *ProviderProviderTargetProperty) HasType() bool` +`func (o *TargetConfigProperty) HasType() bool` HasType returns a boolean if a field has been set. diff --git a/pkg/apiclient/docs/TargetDTO.md b/pkg/apiclient/docs/TargetDTO.md new file mode 100644 index 0000000000..16478ea305 --- /dev/null +++ b/pkg/apiclient/docs/TargetDTO.md @@ -0,0 +1,302 @@ +# TargetDTO + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Default** | **bool** | | +**EnvVars** | **map[string]string** | | +**Id** | **string** | | +**LastJob** | Pointer to [**Job**](Job.md) | | [optional] +**LastJobId** | Pointer to **string** | | [optional] +**Metadata** | Pointer to [**TargetMetadata**](TargetMetadata.md) | | [optional] +**Name** | **string** | | +**ProviderMetadata** | Pointer to **string** | | [optional] +**State** | [**ResourceState**](ResourceState.md) | | +**TargetConfig** | [**TargetConfig**](TargetConfig.md) | | +**TargetConfigId** | **string** | | +**Workspaces** | [**[]Workspace**](Workspace.md) | | + +## Methods + +### NewTargetDTO + +`func NewTargetDTO(default_ bool, envVars map[string]string, id string, name string, state ResourceState, targetConfig TargetConfig, targetConfigId string, workspaces []Workspace, ) *TargetDTO` + +NewTargetDTO instantiates a new TargetDTO object +This constructor will assign default values to properties that have it defined, +and makes sure properties required by API are set, but the set of arguments +will change when the set of required properties is changed + +### NewTargetDTOWithDefaults + +`func NewTargetDTOWithDefaults() *TargetDTO` + +NewTargetDTOWithDefaults instantiates a new TargetDTO object +This constructor will only assign default values to properties that have it defined, +but it doesn't guarantee that properties required by API are set + +### GetDefault + +`func (o *TargetDTO) GetDefault() bool` + +GetDefault returns the Default field if non-nil, zero value otherwise. + +### GetDefaultOk + +`func (o *TargetDTO) GetDefaultOk() (*bool, bool)` + +GetDefaultOk returns a tuple with the Default field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetDefault + +`func (o *TargetDTO) SetDefault(v bool)` + +SetDefault sets Default field to given value. + + +### GetEnvVars + +`func (o *TargetDTO) GetEnvVars() map[string]string` + +GetEnvVars returns the EnvVars field if non-nil, zero value otherwise. + +### GetEnvVarsOk + +`func (o *TargetDTO) GetEnvVarsOk() (*map[string]string, bool)` + +GetEnvVarsOk returns a tuple with the EnvVars field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetEnvVars + +`func (o *TargetDTO) SetEnvVars(v map[string]string)` + +SetEnvVars sets EnvVars field to given value. + + +### GetId + +`func (o *TargetDTO) GetId() string` + +GetId returns the Id field if non-nil, zero value otherwise. + +### GetIdOk + +`func (o *TargetDTO) GetIdOk() (*string, bool)` + +GetIdOk returns a tuple with the Id field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetId + +`func (o *TargetDTO) SetId(v string)` + +SetId sets Id field to given value. + + +### GetLastJob + +`func (o *TargetDTO) GetLastJob() Job` + +GetLastJob returns the LastJob field if non-nil, zero value otherwise. + +### GetLastJobOk + +`func (o *TargetDTO) GetLastJobOk() (*Job, bool)` + +GetLastJobOk returns a tuple with the LastJob field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetLastJob + +`func (o *TargetDTO) SetLastJob(v Job)` + +SetLastJob sets LastJob field to given value. + +### HasLastJob + +`func (o *TargetDTO) HasLastJob() bool` + +HasLastJob returns a boolean if a field has been set. + +### GetLastJobId + +`func (o *TargetDTO) GetLastJobId() string` + +GetLastJobId returns the LastJobId field if non-nil, zero value otherwise. + +### GetLastJobIdOk + +`func (o *TargetDTO) GetLastJobIdOk() (*string, bool)` + +GetLastJobIdOk returns a tuple with the LastJobId field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetLastJobId + +`func (o *TargetDTO) SetLastJobId(v string)` + +SetLastJobId sets LastJobId field to given value. + +### HasLastJobId + +`func (o *TargetDTO) HasLastJobId() bool` + +HasLastJobId returns a boolean if a field has been set. + +### GetMetadata + +`func (o *TargetDTO) GetMetadata() TargetMetadata` + +GetMetadata returns the Metadata field if non-nil, zero value otherwise. + +### GetMetadataOk + +`func (o *TargetDTO) GetMetadataOk() (*TargetMetadata, bool)` + +GetMetadataOk returns a tuple with the Metadata field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetMetadata + +`func (o *TargetDTO) SetMetadata(v TargetMetadata)` + +SetMetadata sets Metadata field to given value. + +### HasMetadata + +`func (o *TargetDTO) HasMetadata() bool` + +HasMetadata returns a boolean if a field has been set. + +### GetName + +`func (o *TargetDTO) GetName() string` + +GetName returns the Name field if non-nil, zero value otherwise. + +### GetNameOk + +`func (o *TargetDTO) GetNameOk() (*string, bool)` + +GetNameOk returns a tuple with the Name field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetName + +`func (o *TargetDTO) SetName(v string)` + +SetName sets Name field to given value. + + +### GetProviderMetadata + +`func (o *TargetDTO) GetProviderMetadata() string` + +GetProviderMetadata returns the ProviderMetadata field if non-nil, zero value otherwise. + +### GetProviderMetadataOk + +`func (o *TargetDTO) GetProviderMetadataOk() (*string, bool)` + +GetProviderMetadataOk returns a tuple with the ProviderMetadata field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetProviderMetadata + +`func (o *TargetDTO) SetProviderMetadata(v string)` + +SetProviderMetadata sets ProviderMetadata field to given value. + +### HasProviderMetadata + +`func (o *TargetDTO) HasProviderMetadata() bool` + +HasProviderMetadata returns a boolean if a field has been set. + +### GetState + +`func (o *TargetDTO) GetState() ResourceState` + +GetState returns the State field if non-nil, zero value otherwise. + +### GetStateOk + +`func (o *TargetDTO) GetStateOk() (*ResourceState, bool)` + +GetStateOk returns a tuple with the State field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetState + +`func (o *TargetDTO) SetState(v ResourceState)` + +SetState sets State field to given value. + + +### GetTargetConfig + +`func (o *TargetDTO) GetTargetConfig() TargetConfig` + +GetTargetConfig returns the TargetConfig field if non-nil, zero value otherwise. + +### GetTargetConfigOk + +`func (o *TargetDTO) GetTargetConfigOk() (*TargetConfig, bool)` + +GetTargetConfigOk returns a tuple with the TargetConfig field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetTargetConfig + +`func (o *TargetDTO) SetTargetConfig(v TargetConfig)` + +SetTargetConfig sets TargetConfig field to given value. + + +### GetTargetConfigId + +`func (o *TargetDTO) GetTargetConfigId() string` + +GetTargetConfigId returns the TargetConfigId field if non-nil, zero value otherwise. + +### GetTargetConfigIdOk + +`func (o *TargetDTO) GetTargetConfigIdOk() (*string, bool)` + +GetTargetConfigIdOk returns a tuple with the TargetConfigId field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetTargetConfigId + +`func (o *TargetDTO) SetTargetConfigId(v string)` + +SetTargetConfigId sets TargetConfigId field to given value. + + +### GetWorkspaces + +`func (o *TargetDTO) GetWorkspaces() []Workspace` + +GetWorkspaces returns the Workspaces field if non-nil, zero value otherwise. + +### GetWorkspacesOk + +`func (o *TargetDTO) GetWorkspacesOk() (*[]Workspace, bool)` + +GetWorkspacesOk returns a tuple with the Workspaces field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetWorkspaces + +`func (o *TargetDTO) SetWorkspaces(v []Workspace)` + +SetWorkspaces sets Workspaces field to given value. + + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/pkg/apiclient/docs/TargetMetadata.md b/pkg/apiclient/docs/TargetMetadata.md new file mode 100644 index 0000000000..dca922a12b --- /dev/null +++ b/pkg/apiclient/docs/TargetMetadata.md @@ -0,0 +1,93 @@ +# TargetMetadata + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**TargetId** | **string** | | +**UpdatedAt** | **string** | | +**Uptime** | **int32** | | + +## Methods + +### NewTargetMetadata + +`func NewTargetMetadata(targetId string, updatedAt string, uptime int32, ) *TargetMetadata` + +NewTargetMetadata instantiates a new TargetMetadata object +This constructor will assign default values to properties that have it defined, +and makes sure properties required by API are set, but the set of arguments +will change when the set of required properties is changed + +### NewTargetMetadataWithDefaults + +`func NewTargetMetadataWithDefaults() *TargetMetadata` + +NewTargetMetadataWithDefaults instantiates a new TargetMetadata object +This constructor will only assign default values to properties that have it defined, +but it doesn't guarantee that properties required by API are set + +### GetTargetId + +`func (o *TargetMetadata) GetTargetId() string` + +GetTargetId returns the TargetId field if non-nil, zero value otherwise. + +### GetTargetIdOk + +`func (o *TargetMetadata) GetTargetIdOk() (*string, bool)` + +GetTargetIdOk returns a tuple with the TargetId field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetTargetId + +`func (o *TargetMetadata) SetTargetId(v string)` + +SetTargetId sets TargetId field to given value. + + +### GetUpdatedAt + +`func (o *TargetMetadata) GetUpdatedAt() string` + +GetUpdatedAt returns the UpdatedAt field if non-nil, zero value otherwise. + +### GetUpdatedAtOk + +`func (o *TargetMetadata) GetUpdatedAtOk() (*string, bool)` + +GetUpdatedAtOk returns a tuple with the UpdatedAt field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetUpdatedAt + +`func (o *TargetMetadata) SetUpdatedAt(v string)` + +SetUpdatedAt sets UpdatedAt field to given value. + + +### GetUptime + +`func (o *TargetMetadata) GetUptime() int32` + +GetUptime returns the Uptime field if non-nil, zero value otherwise. + +### GetUptimeOk + +`func (o *TargetMetadata) GetUptimeOk() (*int32, bool)` + +GetUptimeOk returns a tuple with the Uptime field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetUptime + +`func (o *TargetMetadata) SetUptime(v int32)` + +SetUptime sets Uptime field to given value. + + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/pkg/apiclient/docs/UpdateJobState.md b/pkg/apiclient/docs/UpdateJobState.md new file mode 100644 index 0000000000..565f46888f --- /dev/null +++ b/pkg/apiclient/docs/UpdateJobState.md @@ -0,0 +1,77 @@ +# UpdateJobState + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**ErrorMessage** | Pointer to **string** | | [optional] +**State** | [**JobState**](JobState.md) | | + +## Methods + +### NewUpdateJobState + +`func NewUpdateJobState(state JobState, ) *UpdateJobState` + +NewUpdateJobState instantiates a new UpdateJobState object +This constructor will assign default values to properties that have it defined, +and makes sure properties required by API are set, but the set of arguments +will change when the set of required properties is changed + +### NewUpdateJobStateWithDefaults + +`func NewUpdateJobStateWithDefaults() *UpdateJobState` + +NewUpdateJobStateWithDefaults instantiates a new UpdateJobState object +This constructor will only assign default values to properties that have it defined, +but it doesn't guarantee that properties required by API are set + +### GetErrorMessage + +`func (o *UpdateJobState) GetErrorMessage() string` + +GetErrorMessage returns the ErrorMessage field if non-nil, zero value otherwise. + +### GetErrorMessageOk + +`func (o *UpdateJobState) GetErrorMessageOk() (*string, bool)` + +GetErrorMessageOk returns a tuple with the ErrorMessage field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetErrorMessage + +`func (o *UpdateJobState) SetErrorMessage(v string)` + +SetErrorMessage sets ErrorMessage field to given value. + +### HasErrorMessage + +`func (o *UpdateJobState) HasErrorMessage() bool` + +HasErrorMessage returns a boolean if a field has been set. + +### GetState + +`func (o *UpdateJobState) GetState() JobState` + +GetState returns the State field if non-nil, zero value otherwise. + +### GetStateOk + +`func (o *UpdateJobState) GetStateOk() (*JobState, bool)` + +GetStateOk returns a tuple with the State field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetState + +`func (o *UpdateJobState) SetState(v JobState)` + +SetState sets State field to given value. + + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/pkg/apiclient/docs/UpdateRunnerMetadataDTO.md b/pkg/apiclient/docs/UpdateRunnerMetadataDTO.md new file mode 100644 index 0000000000..c4ebd6c663 --- /dev/null +++ b/pkg/apiclient/docs/UpdateRunnerMetadataDTO.md @@ -0,0 +1,98 @@ +# UpdateRunnerMetadataDTO + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Providers** | [**[]ProviderInfo**](ProviderInfo.md) | | +**RunningJobs** | Pointer to **int32** | | [optional] +**Uptime** | **int32** | | + +## Methods + +### NewUpdateRunnerMetadataDTO + +`func NewUpdateRunnerMetadataDTO(providers []ProviderInfo, uptime int32, ) *UpdateRunnerMetadataDTO` + +NewUpdateRunnerMetadataDTO instantiates a new UpdateRunnerMetadataDTO object +This constructor will assign default values to properties that have it defined, +and makes sure properties required by API are set, but the set of arguments +will change when the set of required properties is changed + +### NewUpdateRunnerMetadataDTOWithDefaults + +`func NewUpdateRunnerMetadataDTOWithDefaults() *UpdateRunnerMetadataDTO` + +NewUpdateRunnerMetadataDTOWithDefaults instantiates a new UpdateRunnerMetadataDTO object +This constructor will only assign default values to properties that have it defined, +but it doesn't guarantee that properties required by API are set + +### GetProviders + +`func (o *UpdateRunnerMetadataDTO) GetProviders() []ProviderInfo` + +GetProviders returns the Providers field if non-nil, zero value otherwise. + +### GetProvidersOk + +`func (o *UpdateRunnerMetadataDTO) GetProvidersOk() (*[]ProviderInfo, bool)` + +GetProvidersOk returns a tuple with the Providers field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetProviders + +`func (o *UpdateRunnerMetadataDTO) SetProviders(v []ProviderInfo)` + +SetProviders sets Providers field to given value. + + +### GetRunningJobs + +`func (o *UpdateRunnerMetadataDTO) GetRunningJobs() int32` + +GetRunningJobs returns the RunningJobs field if non-nil, zero value otherwise. + +### GetRunningJobsOk + +`func (o *UpdateRunnerMetadataDTO) GetRunningJobsOk() (*int32, bool)` + +GetRunningJobsOk returns a tuple with the RunningJobs field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetRunningJobs + +`func (o *UpdateRunnerMetadataDTO) SetRunningJobs(v int32)` + +SetRunningJobs sets RunningJobs field to given value. + +### HasRunningJobs + +`func (o *UpdateRunnerMetadataDTO) HasRunningJobs() bool` + +HasRunningJobs returns a boolean if a field has been set. + +### GetUptime + +`func (o *UpdateRunnerMetadataDTO) GetUptime() int32` + +GetUptime returns the Uptime field if non-nil, zero value otherwise. + +### GetUptimeOk + +`func (o *UpdateRunnerMetadataDTO) GetUptimeOk() (*int32, bool)` + +GetUptimeOk returns a tuple with the Uptime field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetUptime + +`func (o *UpdateRunnerMetadataDTO) SetUptime(v int32)` + +SetUptime sets Uptime field to given value. + + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/pkg/apiclient/docs/UpdateTargetMetadataDTO.md b/pkg/apiclient/docs/UpdateTargetMetadataDTO.md new file mode 100644 index 0000000000..d15a2c6812 --- /dev/null +++ b/pkg/apiclient/docs/UpdateTargetMetadataDTO.md @@ -0,0 +1,51 @@ +# UpdateTargetMetadataDTO + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Uptime** | **int32** | | + +## Methods + +### NewUpdateTargetMetadataDTO + +`func NewUpdateTargetMetadataDTO(uptime int32, ) *UpdateTargetMetadataDTO` + +NewUpdateTargetMetadataDTO instantiates a new UpdateTargetMetadataDTO object +This constructor will assign default values to properties that have it defined, +and makes sure properties required by API are set, but the set of arguments +will change when the set of required properties is changed + +### NewUpdateTargetMetadataDTOWithDefaults + +`func NewUpdateTargetMetadataDTOWithDefaults() *UpdateTargetMetadataDTO` + +NewUpdateTargetMetadataDTOWithDefaults instantiates a new UpdateTargetMetadataDTO object +This constructor will only assign default values to properties that have it defined, +but it doesn't guarantee that properties required by API are set + +### GetUptime + +`func (o *UpdateTargetMetadataDTO) GetUptime() int32` + +GetUptime returns the Uptime field if non-nil, zero value otherwise. + +### GetUptimeOk + +`func (o *UpdateTargetMetadataDTO) GetUptimeOk() (*int32, bool)` + +GetUptimeOk returns a tuple with the Uptime field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetUptime + +`func (o *UpdateTargetMetadataDTO) SetUptime(v int32)` + +SetUptime sets Uptime field to given value. + + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/pkg/apiclient/docs/UpdateTargetProviderMetadataDTO.md b/pkg/apiclient/docs/UpdateTargetProviderMetadataDTO.md new file mode 100644 index 0000000000..8f062e03cf --- /dev/null +++ b/pkg/apiclient/docs/UpdateTargetProviderMetadataDTO.md @@ -0,0 +1,51 @@ +# UpdateTargetProviderMetadataDTO + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Metadata** | **string** | | + +## Methods + +### NewUpdateTargetProviderMetadataDTO + +`func NewUpdateTargetProviderMetadataDTO(metadata string, ) *UpdateTargetProviderMetadataDTO` + +NewUpdateTargetProviderMetadataDTO instantiates a new UpdateTargetProviderMetadataDTO object +This constructor will assign default values to properties that have it defined, +and makes sure properties required by API are set, but the set of arguments +will change when the set of required properties is changed + +### NewUpdateTargetProviderMetadataDTOWithDefaults + +`func NewUpdateTargetProviderMetadataDTOWithDefaults() *UpdateTargetProviderMetadataDTO` + +NewUpdateTargetProviderMetadataDTOWithDefaults instantiates a new UpdateTargetProviderMetadataDTO object +This constructor will only assign default values to properties that have it defined, +but it doesn't guarantee that properties required by API are set + +### GetMetadata + +`func (o *UpdateTargetProviderMetadataDTO) GetMetadata() string` + +GetMetadata returns the Metadata field if non-nil, zero value otherwise. + +### GetMetadataOk + +`func (o *UpdateTargetProviderMetadataDTO) GetMetadataOk() (*string, bool)` + +GetMetadataOk returns a tuple with the Metadata field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetMetadata + +`func (o *UpdateTargetProviderMetadataDTO) SetMetadata(v string)` + +SetMetadata sets Metadata field to given value. + + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/pkg/apiclient/docs/SetProjectState.md b/pkg/apiclient/docs/UpdateWorkspaceMetadataDTO.md similarity index 62% rename from pkg/apiclient/docs/SetProjectState.md rename to pkg/apiclient/docs/UpdateWorkspaceMetadataDTO.md index 662ed9d98f..4da7eedeac 100644 --- a/pkg/apiclient/docs/SetProjectState.md +++ b/pkg/apiclient/docs/UpdateWorkspaceMetadataDTO.md @@ -1,4 +1,4 @@ -# SetProjectState +# UpdateWorkspaceMetadataDTO ## Properties @@ -9,64 +9,64 @@ Name | Type | Description | Notes ## Methods -### NewSetProjectState +### NewUpdateWorkspaceMetadataDTO -`func NewSetProjectState(uptime int32, ) *SetProjectState` +`func NewUpdateWorkspaceMetadataDTO(uptime int32, ) *UpdateWorkspaceMetadataDTO` -NewSetProjectState instantiates a new SetProjectState object +NewUpdateWorkspaceMetadataDTO instantiates a new UpdateWorkspaceMetadataDTO object This constructor will assign default values to properties that have it defined, and makes sure properties required by API are set, but the set of arguments will change when the set of required properties is changed -### NewSetProjectStateWithDefaults +### NewUpdateWorkspaceMetadataDTOWithDefaults -`func NewSetProjectStateWithDefaults() *SetProjectState` +`func NewUpdateWorkspaceMetadataDTOWithDefaults() *UpdateWorkspaceMetadataDTO` -NewSetProjectStateWithDefaults instantiates a new SetProjectState object +NewUpdateWorkspaceMetadataDTOWithDefaults instantiates a new UpdateWorkspaceMetadataDTO object This constructor will only assign default values to properties that have it defined, but it doesn't guarantee that properties required by API are set ### GetGitStatus -`func (o *SetProjectState) GetGitStatus() GitStatus` +`func (o *UpdateWorkspaceMetadataDTO) GetGitStatus() GitStatus` GetGitStatus returns the GitStatus field if non-nil, zero value otherwise. ### GetGitStatusOk -`func (o *SetProjectState) GetGitStatusOk() (*GitStatus, bool)` +`func (o *UpdateWorkspaceMetadataDTO) GetGitStatusOk() (*GitStatus, bool)` GetGitStatusOk returns a tuple with the GitStatus field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. ### SetGitStatus -`func (o *SetProjectState) SetGitStatus(v GitStatus)` +`func (o *UpdateWorkspaceMetadataDTO) SetGitStatus(v GitStatus)` SetGitStatus sets GitStatus field to given value. ### HasGitStatus -`func (o *SetProjectState) HasGitStatus() bool` +`func (o *UpdateWorkspaceMetadataDTO) HasGitStatus() bool` HasGitStatus returns a boolean if a field has been set. ### GetUptime -`func (o *SetProjectState) GetUptime() int32` +`func (o *UpdateWorkspaceMetadataDTO) GetUptime() int32` GetUptime returns the Uptime field if non-nil, zero value otherwise. ### GetUptimeOk -`func (o *SetProjectState) GetUptimeOk() (*int32, bool)` +`func (o *UpdateWorkspaceMetadataDTO) GetUptimeOk() (*int32, bool)` GetUptimeOk returns a tuple with the Uptime field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. ### SetUptime -`func (o *SetProjectState) SetUptime(v int32)` +`func (o *UpdateWorkspaceMetadataDTO) SetUptime(v int32)` SetUptime sets Uptime field to given value. diff --git a/pkg/apiclient/docs/UpdateWorkspaceProviderMetadataDTO.md b/pkg/apiclient/docs/UpdateWorkspaceProviderMetadataDTO.md new file mode 100644 index 0000000000..0a521d7b9a --- /dev/null +++ b/pkg/apiclient/docs/UpdateWorkspaceProviderMetadataDTO.md @@ -0,0 +1,51 @@ +# UpdateWorkspaceProviderMetadataDTO + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Metadata** | **string** | | + +## Methods + +### NewUpdateWorkspaceProviderMetadataDTO + +`func NewUpdateWorkspaceProviderMetadataDTO(metadata string, ) *UpdateWorkspaceProviderMetadataDTO` + +NewUpdateWorkspaceProviderMetadataDTO instantiates a new UpdateWorkspaceProviderMetadataDTO object +This constructor will assign default values to properties that have it defined, +and makes sure properties required by API are set, but the set of arguments +will change when the set of required properties is changed + +### NewUpdateWorkspaceProviderMetadataDTOWithDefaults + +`func NewUpdateWorkspaceProviderMetadataDTOWithDefaults() *UpdateWorkspaceProviderMetadataDTO` + +NewUpdateWorkspaceProviderMetadataDTOWithDefaults instantiates a new UpdateWorkspaceProviderMetadataDTO object +This constructor will only assign default values to properties that have it defined, +but it doesn't guarantee that properties required by API are set + +### GetMetadata + +`func (o *UpdateWorkspaceProviderMetadataDTO) GetMetadata() string` + +GetMetadata returns the Metadata field if non-nil, zero value otherwise. + +### GetMetadataOk + +`func (o *UpdateWorkspaceProviderMetadataDTO) GetMetadataOk() (*string, bool)` + +GetMetadataOk returns a tuple with the Metadata field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetMetadata + +`func (o *UpdateWorkspaceProviderMetadataDTO) SetMetadata(v string)` + +SetMetadata sets Metadata field to given value. + + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/pkg/apiclient/docs/Workspace.md b/pkg/apiclient/docs/Workspace.md index 296d9e30c9..bf37d97f4e 100644 --- a/pkg/apiclient/docs/Workspace.md +++ b/pkg/apiclient/docs/Workspace.md @@ -4,16 +4,28 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- +**ApiKey** | **string** | | +**BuildConfig** | Pointer to [**BuildConfig**](BuildConfig.md) | | [optional] +**EnvVars** | **map[string]string** | | +**GitProviderConfigId** | Pointer to **string** | | [optional] **Id** | **string** | | +**Image** | **string** | | +**Labels** | **map[string]string** | | +**LastJob** | Pointer to [**Job**](Job.md) | | [optional] +**LastJobId** | Pointer to **string** | | [optional] +**Metadata** | Pointer to [**WorkspaceMetadata**](WorkspaceMetadata.md) | | [optional] **Name** | **string** | | -**Projects** | [**[]Project**](Project.md) | | -**Target** | **string** | | +**ProviderMetadata** | Pointer to **string** | | [optional] +**Repository** | [**GitRepository**](GitRepository.md) | | +**Target** | [**Target**](Target.md) | | +**TargetId** | **string** | | +**User** | **string** | | ## Methods ### NewWorkspace -`func NewWorkspace(id string, name string, projects []Project, target string, ) *Workspace` +`func NewWorkspace(apiKey string, envVars map[string]string, id string, image string, labels map[string]string, name string, repository GitRepository, target Target, targetId string, user string, ) *Workspace` NewWorkspace instantiates a new Workspace object This constructor will assign default values to properties that have it defined, @@ -28,6 +40,96 @@ NewWorkspaceWithDefaults instantiates a new Workspace object This constructor will only assign default values to properties that have it defined, but it doesn't guarantee that properties required by API are set +### GetApiKey + +`func (o *Workspace) GetApiKey() string` + +GetApiKey returns the ApiKey field if non-nil, zero value otherwise. + +### GetApiKeyOk + +`func (o *Workspace) GetApiKeyOk() (*string, bool)` + +GetApiKeyOk returns a tuple with the ApiKey field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetApiKey + +`func (o *Workspace) SetApiKey(v string)` + +SetApiKey sets ApiKey field to given value. + + +### GetBuildConfig + +`func (o *Workspace) GetBuildConfig() BuildConfig` + +GetBuildConfig returns the BuildConfig field if non-nil, zero value otherwise. + +### GetBuildConfigOk + +`func (o *Workspace) GetBuildConfigOk() (*BuildConfig, bool)` + +GetBuildConfigOk returns a tuple with the BuildConfig field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetBuildConfig + +`func (o *Workspace) SetBuildConfig(v BuildConfig)` + +SetBuildConfig sets BuildConfig field to given value. + +### HasBuildConfig + +`func (o *Workspace) HasBuildConfig() bool` + +HasBuildConfig returns a boolean if a field has been set. + +### GetEnvVars + +`func (o *Workspace) GetEnvVars() map[string]string` + +GetEnvVars returns the EnvVars field if non-nil, zero value otherwise. + +### GetEnvVarsOk + +`func (o *Workspace) GetEnvVarsOk() (*map[string]string, bool)` + +GetEnvVarsOk returns a tuple with the EnvVars field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetEnvVars + +`func (o *Workspace) SetEnvVars(v map[string]string)` + +SetEnvVars sets EnvVars field to given value. + + +### GetGitProviderConfigId + +`func (o *Workspace) GetGitProviderConfigId() string` + +GetGitProviderConfigId returns the GitProviderConfigId field if non-nil, zero value otherwise. + +### GetGitProviderConfigIdOk + +`func (o *Workspace) GetGitProviderConfigIdOk() (*string, bool)` + +GetGitProviderConfigIdOk returns a tuple with the GitProviderConfigId field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetGitProviderConfigId + +`func (o *Workspace) SetGitProviderConfigId(v string)` + +SetGitProviderConfigId sets GitProviderConfigId field to given value. + +### HasGitProviderConfigId + +`func (o *Workspace) HasGitProviderConfigId() bool` + +HasGitProviderConfigId returns a boolean if a field has been set. + ### GetId `func (o *Workspace) GetId() string` @@ -48,6 +150,121 @@ and a boolean to check if the value has been set. SetId sets Id field to given value. +### GetImage + +`func (o *Workspace) GetImage() string` + +GetImage returns the Image field if non-nil, zero value otherwise. + +### GetImageOk + +`func (o *Workspace) GetImageOk() (*string, bool)` + +GetImageOk returns a tuple with the Image field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetImage + +`func (o *Workspace) SetImage(v string)` + +SetImage sets Image field to given value. + + +### GetLabels + +`func (o *Workspace) GetLabels() map[string]string` + +GetLabels returns the Labels field if non-nil, zero value otherwise. + +### GetLabelsOk + +`func (o *Workspace) GetLabelsOk() (*map[string]string, bool)` + +GetLabelsOk returns a tuple with the Labels field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetLabels + +`func (o *Workspace) SetLabels(v map[string]string)` + +SetLabels sets Labels field to given value. + + +### GetLastJob + +`func (o *Workspace) GetLastJob() Job` + +GetLastJob returns the LastJob field if non-nil, zero value otherwise. + +### GetLastJobOk + +`func (o *Workspace) GetLastJobOk() (*Job, bool)` + +GetLastJobOk returns a tuple with the LastJob field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetLastJob + +`func (o *Workspace) SetLastJob(v Job)` + +SetLastJob sets LastJob field to given value. + +### HasLastJob + +`func (o *Workspace) HasLastJob() bool` + +HasLastJob returns a boolean if a field has been set. + +### GetLastJobId + +`func (o *Workspace) GetLastJobId() string` + +GetLastJobId returns the LastJobId field if non-nil, zero value otherwise. + +### GetLastJobIdOk + +`func (o *Workspace) GetLastJobIdOk() (*string, bool)` + +GetLastJobIdOk returns a tuple with the LastJobId field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetLastJobId + +`func (o *Workspace) SetLastJobId(v string)` + +SetLastJobId sets LastJobId field to given value. + +### HasLastJobId + +`func (o *Workspace) HasLastJobId() bool` + +HasLastJobId returns a boolean if a field has been set. + +### GetMetadata + +`func (o *Workspace) GetMetadata() WorkspaceMetadata` + +GetMetadata returns the Metadata field if non-nil, zero value otherwise. + +### GetMetadataOk + +`func (o *Workspace) GetMetadataOk() (*WorkspaceMetadata, bool)` + +GetMetadataOk returns a tuple with the Metadata field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetMetadata + +`func (o *Workspace) SetMetadata(v WorkspaceMetadata)` + +SetMetadata sets Metadata field to given value. + +### HasMetadata + +`func (o *Workspace) HasMetadata() bool` + +HasMetadata returns a boolean if a field has been set. + ### GetName `func (o *Workspace) GetName() string` @@ -68,46 +285,111 @@ and a boolean to check if the value has been set. SetName sets Name field to given value. -### GetProjects +### GetProviderMetadata + +`func (o *Workspace) GetProviderMetadata() string` + +GetProviderMetadata returns the ProviderMetadata field if non-nil, zero value otherwise. + +### GetProviderMetadataOk + +`func (o *Workspace) GetProviderMetadataOk() (*string, bool)` + +GetProviderMetadataOk returns a tuple with the ProviderMetadata field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetProviderMetadata + +`func (o *Workspace) SetProviderMetadata(v string)` -`func (o *Workspace) GetProjects() []Project` +SetProviderMetadata sets ProviderMetadata field to given value. -GetProjects returns the Projects field if non-nil, zero value otherwise. +### HasProviderMetadata -### GetProjectsOk +`func (o *Workspace) HasProviderMetadata() bool` -`func (o *Workspace) GetProjectsOk() (*[]Project, bool)` +HasProviderMetadata returns a boolean if a field has been set. -GetProjectsOk returns a tuple with the Projects field if it's non-nil, zero value otherwise +### GetRepository + +`func (o *Workspace) GetRepository() GitRepository` + +GetRepository returns the Repository field if non-nil, zero value otherwise. + +### GetRepositoryOk + +`func (o *Workspace) GetRepositoryOk() (*GitRepository, bool)` + +GetRepositoryOk returns a tuple with the Repository field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. -### SetProjects +### SetRepository -`func (o *Workspace) SetProjects(v []Project)` +`func (o *Workspace) SetRepository(v GitRepository)` -SetProjects sets Projects field to given value. +SetRepository sets Repository field to given value. ### GetTarget -`func (o *Workspace) GetTarget() string` +`func (o *Workspace) GetTarget() Target` GetTarget returns the Target field if non-nil, zero value otherwise. ### GetTargetOk -`func (o *Workspace) GetTargetOk() (*string, bool)` +`func (o *Workspace) GetTargetOk() (*Target, bool)` GetTargetOk returns a tuple with the Target field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. ### SetTarget -`func (o *Workspace) SetTarget(v string)` +`func (o *Workspace) SetTarget(v Target)` SetTarget sets Target field to given value. +### GetTargetId + +`func (o *Workspace) GetTargetId() string` + +GetTargetId returns the TargetId field if non-nil, zero value otherwise. + +### GetTargetIdOk + +`func (o *Workspace) GetTargetIdOk() (*string, bool)` + +GetTargetIdOk returns a tuple with the TargetId field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetTargetId + +`func (o *Workspace) SetTargetId(v string)` + +SetTargetId sets TargetId field to given value. + + +### GetUser + +`func (o *Workspace) GetUser() string` + +GetUser returns the User field if non-nil, zero value otherwise. + +### GetUserOk + +`func (o *Workspace) GetUserOk() (*string, bool)` + +GetUserOk returns a tuple with the User field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetUser + +`func (o *Workspace) SetUser(v string)` + +SetUser sets User field to given value. + + [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pkg/apiclient/docs/WorkspaceAPI.md b/pkg/apiclient/docs/WorkspaceAPI.md index 34e40fa02e..5335976763 100644 --- a/pkg/apiclient/docs/WorkspaceAPI.md +++ b/pkg/apiclient/docs/WorkspaceAPI.md @@ -5,20 +5,22 @@ All URIs are relative to *http://localhost:3986* Method | HTTP request | Description ------------- | ------------- | ------------- [**CreateWorkspace**](WorkspaceAPI.md#CreateWorkspace) | **Post** /workspace | Create a workspace -[**GetWorkspace**](WorkspaceAPI.md#GetWorkspace) | **Get** /workspace/{workspaceId} | Get workspace info +[**DeleteWorkspace**](WorkspaceAPI.md#DeleteWorkspace) | **Delete** /workspace/{workspaceId} | Delete workspace +[**FindWorkspace**](WorkspaceAPI.md#FindWorkspace) | **Get** /workspace/{workspaceId} | Find workspace +[**GetWorkspaceState**](WorkspaceAPI.md#GetWorkspaceState) | **Get** /workspace/{workspaceId}/state | Get workspace state [**ListWorkspaces**](WorkspaceAPI.md#ListWorkspaces) | **Get** /workspace | List workspaces -[**RemoveWorkspace**](WorkspaceAPI.md#RemoveWorkspace) | **Delete** /workspace/{workspaceId} | Remove workspace -[**SetProjectState**](WorkspaceAPI.md#SetProjectState) | **Post** /workspace/{workspaceId}/{projectId}/state | Set project state -[**StartProject**](WorkspaceAPI.md#StartProject) | **Post** /workspace/{workspaceId}/{projectId}/start | Start project +[**RestartWorkspace**](WorkspaceAPI.md#RestartWorkspace) | **Post** /workspace/{workspaceId}/restart | Restart workspace [**StartWorkspace**](WorkspaceAPI.md#StartWorkspace) | **Post** /workspace/{workspaceId}/start | Start workspace -[**StopProject**](WorkspaceAPI.md#StopProject) | **Post** /workspace/{workspaceId}/{projectId}/stop | Stop project [**StopWorkspace**](WorkspaceAPI.md#StopWorkspace) | **Post** /workspace/{workspaceId}/stop | Stop workspace +[**UpdateWorkspaceLabels**](WorkspaceAPI.md#UpdateWorkspaceLabels) | **Post** /workspace/{workspaceId}/labels | Update workspace labels +[**UpdateWorkspaceMetadata**](WorkspaceAPI.md#UpdateWorkspaceMetadata) | **Post** /workspace/{workspaceId}/metadata | Update workspace metadata +[**UpdateWorkspaceProviderMetadata**](WorkspaceAPI.md#UpdateWorkspaceProviderMetadata) | **Post** /workspace/{workspaceId}/provider-metadata | Update workspace provider metadata ## CreateWorkspace -> Workspace CreateWorkspace(ctx).Workspace(workspace).Execute() +> WorkspaceDTO CreateWorkspace(ctx).Workspace(workspace).Execute() Create a workspace @@ -37,7 +39,7 @@ import ( ) func main() { - workspace := *openapiclient.NewCreateWorkspaceDTO("Id_example", "Name_example", []openapiclient.CreateProjectDTO{*openapiclient.NewCreateProjectDTO(map[string]string{"key": "Inner_example"}, "Name_example", *openapiclient.NewCreateProjectSourceDTO(*openapiclient.NewGitRepository("Branch_example", "Id_example", "Name_example", "Owner_example", "Sha_example", "Source_example", "Url_example")))}, "Target_example") // CreateWorkspaceDTO | Create workspace + workspace := *openapiclient.NewCreateWorkspaceDTO(map[string]string{"key": "Inner_example"}, "Id_example", map[string]string{"key": "Inner_example"}, "Name_example", *openapiclient.NewCreateWorkspaceSourceDTO(*openapiclient.NewGitRepository("Branch_example", "Id_example", "Name_example", "Owner_example", "Sha_example", "Source_example", "Url_example")), "TargetId_example") // CreateWorkspaceDTO | Create workspace configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) @@ -46,7 +48,7 @@ func main() { fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceAPI.CreateWorkspace``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) } - // response from `CreateWorkspace`: Workspace + // response from `CreateWorkspace`: WorkspaceDTO fmt.Fprintf(os.Stdout, "Response from `WorkspaceAPI.CreateWorkspace`: %v\n", resp) } ``` @@ -66,7 +68,7 @@ Name | Type | Description | Notes ### Return type -[**Workspace**](Workspace.md) +[**WorkspaceDTO**](WorkspaceDTO.md) ### Authorization @@ -82,11 +84,81 @@ Name | Type | Description | Notes [[Back to README]](../README.md) -## GetWorkspace +## DeleteWorkspace -> WorkspaceDTO GetWorkspace(ctx, workspaceId).Verbose(verbose).Execute() +> DeleteWorkspace(ctx, workspaceId).Force(force).Execute() -Get workspace info +Delete workspace + + + +### Example + +```go +package main + +import ( + "context" + "fmt" + "os" + openapiclient "github.com/GIT_USER_ID/GIT_REPO_ID/apiclient" +) + +func main() { + workspaceId := "workspaceId_example" // string | Workspace ID + force := true // bool | Force (optional) + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + r, err := apiClient.WorkspaceAPI.DeleteWorkspace(context.Background(), workspaceId).Force(force).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceAPI.DeleteWorkspace``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } +} +``` + +### Path Parameters + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- +**ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. +**workspaceId** | **string** | Workspace ID | + +### Other Parameters + +Other parameters are passed through a pointer to a apiDeleteWorkspaceRequest struct via the builder pattern + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + + **force** | **bool** | Force | + +### Return type + + (empty response body) + +### Authorization + +[Bearer](../README.md#Bearer) + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: Not defined + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) +[[Back to Model list]](../README.md#documentation-for-models) +[[Back to README]](../README.md) + + +## FindWorkspace + +> WorkspaceDTO FindWorkspace(ctx, workspaceId).Execute() + +Find workspace @@ -104,17 +176,16 @@ import ( func main() { workspaceId := "workspaceId_example" // string | Workspace ID or Name - verbose := true // bool | Verbose (optional) configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.WorkspaceAPI.GetWorkspace(context.Background(), workspaceId).Verbose(verbose).Execute() + resp, r, err := apiClient.WorkspaceAPI.FindWorkspace(context.Background(), workspaceId).Execute() if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceAPI.GetWorkspace``: %v\n", err) + fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceAPI.FindWorkspace``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) } - // response from `GetWorkspace`: WorkspaceDTO - fmt.Fprintf(os.Stdout, "Response from `WorkspaceAPI.GetWorkspace`: %v\n", resp) + // response from `FindWorkspace`: WorkspaceDTO + fmt.Fprintf(os.Stdout, "Response from `WorkspaceAPI.FindWorkspace`: %v\n", resp) } ``` @@ -128,13 +199,12 @@ Name | Type | Description | Notes ### Other Parameters -Other parameters are passed through a pointer to a apiGetWorkspaceRequest struct via the builder pattern +Other parameters are passed through a pointer to a apiFindWorkspaceRequest struct via the builder pattern Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - **verbose** | **bool** | Verbose | ### Return type @@ -154,9 +224,79 @@ Name | Type | Description | Notes [[Back to README]](../README.md) +## GetWorkspaceState + +> ResourceState GetWorkspaceState(ctx, workspaceId).Execute() + +Get workspace state + + + +### Example + +```go +package main + +import ( + "context" + "fmt" + "os" + openapiclient "github.com/GIT_USER_ID/GIT_REPO_ID/apiclient" +) + +func main() { + workspaceId := "workspaceId_example" // string | Workspace ID or Name + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.WorkspaceAPI.GetWorkspaceState(context.Background(), workspaceId).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceAPI.GetWorkspaceState``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `GetWorkspaceState`: ResourceState + fmt.Fprintf(os.Stdout, "Response from `WorkspaceAPI.GetWorkspaceState`: %v\n", resp) +} +``` + +### Path Parameters + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- +**ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. +**workspaceId** | **string** | Workspace ID or Name | + +### Other Parameters + +Other parameters are passed through a pointer to a apiGetWorkspaceStateRequest struct via the builder pattern + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + + +### Return type + +[**ResourceState**](ResourceState.md) + +### Authorization + +[Bearer](../README.md#Bearer) + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) +[[Back to Model list]](../README.md#documentation-for-models) +[[Back to README]](../README.md) + + ## ListWorkspaces -> []WorkspaceDTO ListWorkspaces(ctx).Verbose(verbose).Execute() +> []WorkspaceDTO ListWorkspaces(ctx).Labels(labels).Execute() List workspaces @@ -175,11 +315,11 @@ import ( ) func main() { - verbose := true // bool | Verbose (optional) + labels := "labels_example" // string | JSON encoded labels (optional) configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.WorkspaceAPI.ListWorkspaces(context.Background()).Verbose(verbose).Execute() + resp, r, err := apiClient.WorkspaceAPI.ListWorkspaces(context.Background()).Labels(labels).Execute() if err != nil { fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceAPI.ListWorkspaces``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) @@ -200,7 +340,7 @@ Other parameters are passed through a pointer to a apiListWorkspacesRequest stru Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - **verbose** | **bool** | Verbose | + **labels** | **string** | JSON encoded labels | ### Return type @@ -220,11 +360,11 @@ Name | Type | Description | Notes [[Back to README]](../README.md) -## RemoveWorkspace +## RestartWorkspace -> RemoveWorkspace(ctx, workspaceId).Force(force).Execute() +> RestartWorkspace(ctx, workspaceId).Execute() -Remove workspace +Restart workspace @@ -241,14 +381,13 @@ import ( ) func main() { - workspaceId := "workspaceId_example" // string | Workspace ID - force := true // bool | Force (optional) + workspaceId := "workspaceId_example" // string | Workspace ID or Name configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - r, err := apiClient.WorkspaceAPI.RemoveWorkspace(context.Background(), workspaceId).Force(force).Execute() + r, err := apiClient.WorkspaceAPI.RestartWorkspace(context.Background(), workspaceId).Execute() if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceAPI.RemoveWorkspace``: %v\n", err) + fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceAPI.RestartWorkspace``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) } } @@ -260,17 +399,16 @@ func main() { Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. -**workspaceId** | **string** | Workspace ID | +**workspaceId** | **string** | Workspace ID or Name | ### Other Parameters -Other parameters are passed through a pointer to a apiRemoveWorkspaceRequest struct via the builder pattern +Other parameters are passed through a pointer to a apiRestartWorkspaceRequest struct via the builder pattern Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - **force** | **bool** | Force | ### Return type @@ -290,11 +428,11 @@ Name | Type | Description | Notes [[Back to README]](../README.md) -## SetProjectState +## StartWorkspace -> SetProjectState(ctx, workspaceId, projectId).SetState(setState).Execute() +> StartWorkspace(ctx, workspaceId).Execute() -Set project state +Start workspace @@ -312,14 +450,12 @@ import ( func main() { workspaceId := "workspaceId_example" // string | Workspace ID or Name - projectId := "projectId_example" // string | Project ID - setState := *openapiclient.NewSetProjectState(int32(123)) // SetProjectState | Set State configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - r, err := apiClient.WorkspaceAPI.SetProjectState(context.Background(), workspaceId, projectId).SetState(setState).Execute() + r, err := apiClient.WorkspaceAPI.StartWorkspace(context.Background(), workspaceId).Execute() if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceAPI.SetProjectState``: %v\n", err) + fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceAPI.StartWorkspace``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) } } @@ -332,19 +468,16 @@ Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. **workspaceId** | **string** | Workspace ID or Name | -**projectId** | **string** | Project ID | ### Other Parameters -Other parameters are passed through a pointer to a apiSetProjectStateRequest struct via the builder pattern +Other parameters are passed through a pointer to a apiStartWorkspaceRequest struct via the builder pattern Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - **setState** | [**SetProjectState**](SetProjectState.md) | Set State | - ### Return type (empty response body) @@ -363,11 +496,11 @@ Name | Type | Description | Notes [[Back to README]](../README.md) -## StartProject +## StopWorkspace -> StartProject(ctx, workspaceId, projectId).Execute() +> StopWorkspace(ctx, workspaceId).Execute() -Start project +Stop workspace @@ -385,13 +518,12 @@ import ( func main() { workspaceId := "workspaceId_example" // string | Workspace ID or Name - projectId := "projectId_example" // string | Project ID configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - r, err := apiClient.WorkspaceAPI.StartProject(context.Background(), workspaceId, projectId).Execute() + r, err := apiClient.WorkspaceAPI.StopWorkspace(context.Background(), workspaceId).Execute() if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceAPI.StartProject``: %v\n", err) + fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceAPI.StopWorkspace``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) } } @@ -404,18 +536,16 @@ Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. **workspaceId** | **string** | Workspace ID or Name | -**projectId** | **string** | Project ID | ### Other Parameters -Other parameters are passed through a pointer to a apiStartProjectRequest struct via the builder pattern +Other parameters are passed through a pointer to a apiStopWorkspaceRequest struct via the builder pattern Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - ### Return type (empty response body) @@ -434,11 +564,11 @@ Name | Type | Description | Notes [[Back to README]](../README.md) -## StartWorkspace +## UpdateWorkspaceLabels -> StartWorkspace(ctx, workspaceId).Execute() +> WorkspaceDTO UpdateWorkspaceLabels(ctx, workspaceId).Labels(labels).Execute() -Start workspace +Update workspace labels @@ -456,14 +586,17 @@ import ( func main() { workspaceId := "workspaceId_example" // string | Workspace ID or Name + labels := map[string]string{"key": "Inner_example"} // map[string]string | Labels configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - r, err := apiClient.WorkspaceAPI.StartWorkspace(context.Background(), workspaceId).Execute() + resp, r, err := apiClient.WorkspaceAPI.UpdateWorkspaceLabels(context.Background(), workspaceId).Labels(labels).Execute() if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceAPI.StartWorkspace``: %v\n", err) + fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceAPI.UpdateWorkspaceLabels``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) } + // response from `UpdateWorkspaceLabels`: WorkspaceDTO + fmt.Fprintf(os.Stdout, "Response from `WorkspaceAPI.UpdateWorkspaceLabels`: %v\n", resp) } ``` @@ -477,16 +610,17 @@ Name | Type | Description | Notes ### Other Parameters -Other parameters are passed through a pointer to a apiStartWorkspaceRequest struct via the builder pattern +Other parameters are passed through a pointer to a apiUpdateWorkspaceLabelsRequest struct via the builder pattern Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- + **labels** | **map[string]string** | Labels | ### Return type - (empty response body) +[**WorkspaceDTO**](WorkspaceDTO.md) ### Authorization @@ -495,18 +629,18 @@ Name | Type | Description | Notes ### HTTP request headers - **Content-Type**: Not defined -- **Accept**: Not defined +- **Accept**: */* [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) -## StopProject +## UpdateWorkspaceMetadata -> StopProject(ctx, workspaceId, projectId).Execute() +> UpdateWorkspaceMetadata(ctx, workspaceId).WorkspaceMetadata(workspaceMetadata).Execute() -Stop project +Update workspace metadata @@ -523,14 +657,14 @@ import ( ) func main() { - workspaceId := "workspaceId_example" // string | Workspace ID or Name - projectId := "projectId_example" // string | Project ID + workspaceId := "workspaceId_example" // string | Workspace ID + workspaceMetadata := *openapiclient.NewUpdateWorkspaceMetadataDTO(int32(123)) // UpdateWorkspaceMetadataDTO | Workspace Metadata configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - r, err := apiClient.WorkspaceAPI.StopProject(context.Background(), workspaceId, projectId).Execute() + r, err := apiClient.WorkspaceAPI.UpdateWorkspaceMetadata(context.Background(), workspaceId).WorkspaceMetadata(workspaceMetadata).Execute() if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceAPI.StopProject``: %v\n", err) + fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceAPI.UpdateWorkspaceMetadata``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) } } @@ -542,18 +676,17 @@ func main() { Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. -**workspaceId** | **string** | Workspace ID or Name | -**projectId** | **string** | Project ID | +**workspaceId** | **string** | Workspace ID | ### Other Parameters -Other parameters are passed through a pointer to a apiStopProjectRequest struct via the builder pattern +Other parameters are passed through a pointer to a apiUpdateWorkspaceMetadataRequest struct via the builder pattern Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - + **workspaceMetadata** | [**UpdateWorkspaceMetadataDTO**](UpdateWorkspaceMetadataDTO.md) | Workspace Metadata | ### Return type @@ -573,11 +706,11 @@ Name | Type | Description | Notes [[Back to README]](../README.md) -## StopWorkspace +## UpdateWorkspaceProviderMetadata -> StopWorkspace(ctx, workspaceId).Execute() +> UpdateWorkspaceProviderMetadata(ctx, workspaceId).Metadata(metadata).Execute() -Stop workspace +Update workspace provider metadata @@ -594,13 +727,14 @@ import ( ) func main() { - workspaceId := "workspaceId_example" // string | Workspace ID or Name + workspaceId := "workspaceId_example" // string | Workspace ID + metadata := *openapiclient.NewUpdateWorkspaceProviderMetadataDTO("Metadata_example") // UpdateWorkspaceProviderMetadataDTO | Provider metadata configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - r, err := apiClient.WorkspaceAPI.StopWorkspace(context.Background(), workspaceId).Execute() + r, err := apiClient.WorkspaceAPI.UpdateWorkspaceProviderMetadata(context.Background(), workspaceId).Metadata(metadata).Execute() if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceAPI.StopWorkspace``: %v\n", err) + fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceAPI.UpdateWorkspaceProviderMetadata``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) } } @@ -612,16 +746,17 @@ func main() { Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. -**workspaceId** | **string** | Workspace ID or Name | +**workspaceId** | **string** | Workspace ID | ### Other Parameters -Other parameters are passed through a pointer to a apiStopWorkspaceRequest struct via the builder pattern +Other parameters are passed through a pointer to a apiUpdateWorkspaceProviderMetadataRequest struct via the builder pattern Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- + **metadata** | [**UpdateWorkspaceProviderMetadataDTO**](UpdateWorkspaceProviderMetadataDTO.md) | Provider metadata | ### Return type diff --git a/pkg/apiclient/docs/WorkspaceDTO.md b/pkg/apiclient/docs/WorkspaceDTO.md index 9a0ce569c3..8e1f5e327a 100644 --- a/pkg/apiclient/docs/WorkspaceDTO.md +++ b/pkg/apiclient/docs/WorkspaceDTO.md @@ -4,17 +4,29 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- +**ApiKey** | **string** | | +**BuildConfig** | Pointer to [**BuildConfig**](BuildConfig.md) | | [optional] +**EnvVars** | **map[string]string** | | +**GitProviderConfigId** | Pointer to **string** | | [optional] **Id** | **string** | | -**Info** | Pointer to [**WorkspaceInfo**](WorkspaceInfo.md) | | [optional] +**Image** | **string** | | +**Labels** | **map[string]string** | | +**LastJob** | Pointer to [**Job**](Job.md) | | [optional] +**LastJobId** | Pointer to **string** | | [optional] +**Metadata** | Pointer to [**WorkspaceMetadata**](WorkspaceMetadata.md) | | [optional] **Name** | **string** | | -**Projects** | [**[]Project**](Project.md) | | -**Target** | **string** | | +**ProviderMetadata** | Pointer to **string** | | [optional] +**Repository** | [**GitRepository**](GitRepository.md) | | +**State** | [**ResourceState**](ResourceState.md) | | +**Target** | [**Target**](Target.md) | | +**TargetId** | **string** | | +**User** | **string** | | ## Methods ### NewWorkspaceDTO -`func NewWorkspaceDTO(id string, name string, projects []Project, target string, ) *WorkspaceDTO` +`func NewWorkspaceDTO(apiKey string, envVars map[string]string, id string, image string, labels map[string]string, name string, repository GitRepository, state ResourceState, target Target, targetId string, user string, ) *WorkspaceDTO` NewWorkspaceDTO instantiates a new WorkspaceDTO object This constructor will assign default values to properties that have it defined, @@ -29,6 +41,96 @@ NewWorkspaceDTOWithDefaults instantiates a new WorkspaceDTO object This constructor will only assign default values to properties that have it defined, but it doesn't guarantee that properties required by API are set +### GetApiKey + +`func (o *WorkspaceDTO) GetApiKey() string` + +GetApiKey returns the ApiKey field if non-nil, zero value otherwise. + +### GetApiKeyOk + +`func (o *WorkspaceDTO) GetApiKeyOk() (*string, bool)` + +GetApiKeyOk returns a tuple with the ApiKey field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetApiKey + +`func (o *WorkspaceDTO) SetApiKey(v string)` + +SetApiKey sets ApiKey field to given value. + + +### GetBuildConfig + +`func (o *WorkspaceDTO) GetBuildConfig() BuildConfig` + +GetBuildConfig returns the BuildConfig field if non-nil, zero value otherwise. + +### GetBuildConfigOk + +`func (o *WorkspaceDTO) GetBuildConfigOk() (*BuildConfig, bool)` + +GetBuildConfigOk returns a tuple with the BuildConfig field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetBuildConfig + +`func (o *WorkspaceDTO) SetBuildConfig(v BuildConfig)` + +SetBuildConfig sets BuildConfig field to given value. + +### HasBuildConfig + +`func (o *WorkspaceDTO) HasBuildConfig() bool` + +HasBuildConfig returns a boolean if a field has been set. + +### GetEnvVars + +`func (o *WorkspaceDTO) GetEnvVars() map[string]string` + +GetEnvVars returns the EnvVars field if non-nil, zero value otherwise. + +### GetEnvVarsOk + +`func (o *WorkspaceDTO) GetEnvVarsOk() (*map[string]string, bool)` + +GetEnvVarsOk returns a tuple with the EnvVars field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetEnvVars + +`func (o *WorkspaceDTO) SetEnvVars(v map[string]string)` + +SetEnvVars sets EnvVars field to given value. + + +### GetGitProviderConfigId + +`func (o *WorkspaceDTO) GetGitProviderConfigId() string` + +GetGitProviderConfigId returns the GitProviderConfigId field if non-nil, zero value otherwise. + +### GetGitProviderConfigIdOk + +`func (o *WorkspaceDTO) GetGitProviderConfigIdOk() (*string, bool)` + +GetGitProviderConfigIdOk returns a tuple with the GitProviderConfigId field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetGitProviderConfigId + +`func (o *WorkspaceDTO) SetGitProviderConfigId(v string)` + +SetGitProviderConfigId sets GitProviderConfigId field to given value. + +### HasGitProviderConfigId + +`func (o *WorkspaceDTO) HasGitProviderConfigId() bool` + +HasGitProviderConfigId returns a boolean if a field has been set. + ### GetId `func (o *WorkspaceDTO) GetId() string` @@ -49,30 +151,120 @@ and a boolean to check if the value has been set. SetId sets Id field to given value. -### GetInfo +### GetImage + +`func (o *WorkspaceDTO) GetImage() string` + +GetImage returns the Image field if non-nil, zero value otherwise. + +### GetImageOk + +`func (o *WorkspaceDTO) GetImageOk() (*string, bool)` + +GetImageOk returns a tuple with the Image field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetImage + +`func (o *WorkspaceDTO) SetImage(v string)` + +SetImage sets Image field to given value. + + +### GetLabels + +`func (o *WorkspaceDTO) GetLabels() map[string]string` + +GetLabels returns the Labels field if non-nil, zero value otherwise. + +### GetLabelsOk + +`func (o *WorkspaceDTO) GetLabelsOk() (*map[string]string, bool)` + +GetLabelsOk returns a tuple with the Labels field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetLabels + +`func (o *WorkspaceDTO) SetLabels(v map[string]string)` + +SetLabels sets Labels field to given value. + + +### GetLastJob + +`func (o *WorkspaceDTO) GetLastJob() Job` -`func (o *WorkspaceDTO) GetInfo() WorkspaceInfo` +GetLastJob returns the LastJob field if non-nil, zero value otherwise. -GetInfo returns the Info field if non-nil, zero value otherwise. +### GetLastJobOk -### GetInfoOk +`func (o *WorkspaceDTO) GetLastJobOk() (*Job, bool)` -`func (o *WorkspaceDTO) GetInfoOk() (*WorkspaceInfo, bool)` +GetLastJobOk returns a tuple with the LastJob field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetLastJob + +`func (o *WorkspaceDTO) SetLastJob(v Job)` + +SetLastJob sets LastJob field to given value. + +### HasLastJob + +`func (o *WorkspaceDTO) HasLastJob() bool` + +HasLastJob returns a boolean if a field has been set. + +### GetLastJobId + +`func (o *WorkspaceDTO) GetLastJobId() string` + +GetLastJobId returns the LastJobId field if non-nil, zero value otherwise. + +### GetLastJobIdOk + +`func (o *WorkspaceDTO) GetLastJobIdOk() (*string, bool)` + +GetLastJobIdOk returns a tuple with the LastJobId field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetLastJobId + +`func (o *WorkspaceDTO) SetLastJobId(v string)` + +SetLastJobId sets LastJobId field to given value. + +### HasLastJobId -GetInfoOk returns a tuple with the Info field if it's non-nil, zero value otherwise +`func (o *WorkspaceDTO) HasLastJobId() bool` + +HasLastJobId returns a boolean if a field has been set. + +### GetMetadata + +`func (o *WorkspaceDTO) GetMetadata() WorkspaceMetadata` + +GetMetadata returns the Metadata field if non-nil, zero value otherwise. + +### GetMetadataOk + +`func (o *WorkspaceDTO) GetMetadataOk() (*WorkspaceMetadata, bool)` + +GetMetadataOk returns a tuple with the Metadata field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. -### SetInfo +### SetMetadata -`func (o *WorkspaceDTO) SetInfo(v WorkspaceInfo)` +`func (o *WorkspaceDTO) SetMetadata(v WorkspaceMetadata)` -SetInfo sets Info field to given value. +SetMetadata sets Metadata field to given value. -### HasInfo +### HasMetadata -`func (o *WorkspaceDTO) HasInfo() bool` +`func (o *WorkspaceDTO) HasMetadata() bool` -HasInfo returns a boolean if a field has been set. +HasMetadata returns a boolean if a field has been set. ### GetName @@ -94,46 +286,131 @@ and a boolean to check if the value has been set. SetName sets Name field to given value. -### GetProjects +### GetProviderMetadata -`func (o *WorkspaceDTO) GetProjects() []Project` +`func (o *WorkspaceDTO) GetProviderMetadata() string` -GetProjects returns the Projects field if non-nil, zero value otherwise. +GetProviderMetadata returns the ProviderMetadata field if non-nil, zero value otherwise. -### GetProjectsOk +### GetProviderMetadataOk -`func (o *WorkspaceDTO) GetProjectsOk() (*[]Project, bool)` +`func (o *WorkspaceDTO) GetProviderMetadataOk() (*string, bool)` -GetProjectsOk returns a tuple with the Projects field if it's non-nil, zero value otherwise +GetProviderMetadataOk returns a tuple with the ProviderMetadata field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. -### SetProjects +### SetProviderMetadata + +`func (o *WorkspaceDTO) SetProviderMetadata(v string)` + +SetProviderMetadata sets ProviderMetadata field to given value. -`func (o *WorkspaceDTO) SetProjects(v []Project)` +### HasProviderMetadata + +`func (o *WorkspaceDTO) HasProviderMetadata() bool` + +HasProviderMetadata returns a boolean if a field has been set. + +### GetRepository + +`func (o *WorkspaceDTO) GetRepository() GitRepository` + +GetRepository returns the Repository field if non-nil, zero value otherwise. + +### GetRepositoryOk + +`func (o *WorkspaceDTO) GetRepositoryOk() (*GitRepository, bool)` + +GetRepositoryOk returns a tuple with the Repository field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. -SetProjects sets Projects field to given value. +### SetRepository + +`func (o *WorkspaceDTO) SetRepository(v GitRepository)` + +SetRepository sets Repository field to given value. + + +### GetState + +`func (o *WorkspaceDTO) GetState() ResourceState` + +GetState returns the State field if non-nil, zero value otherwise. + +### GetStateOk + +`func (o *WorkspaceDTO) GetStateOk() (*ResourceState, bool)` + +GetStateOk returns a tuple with the State field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetState + +`func (o *WorkspaceDTO) SetState(v ResourceState)` + +SetState sets State field to given value. ### GetTarget -`func (o *WorkspaceDTO) GetTarget() string` +`func (o *WorkspaceDTO) GetTarget() Target` GetTarget returns the Target field if non-nil, zero value otherwise. ### GetTargetOk -`func (o *WorkspaceDTO) GetTargetOk() (*string, bool)` +`func (o *WorkspaceDTO) GetTargetOk() (*Target, bool)` GetTargetOk returns a tuple with the Target field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. ### SetTarget -`func (o *WorkspaceDTO) SetTarget(v string)` +`func (o *WorkspaceDTO) SetTarget(v Target)` SetTarget sets Target field to given value. +### GetTargetId + +`func (o *WorkspaceDTO) GetTargetId() string` + +GetTargetId returns the TargetId field if non-nil, zero value otherwise. + +### GetTargetIdOk + +`func (o *WorkspaceDTO) GetTargetIdOk() (*string, bool)` + +GetTargetIdOk returns a tuple with the TargetId field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetTargetId + +`func (o *WorkspaceDTO) SetTargetId(v string)` + +SetTargetId sets TargetId field to given value. + + +### GetUser + +`func (o *WorkspaceDTO) GetUser() string` + +GetUser returns the User field if non-nil, zero value otherwise. + +### GetUserOk + +`func (o *WorkspaceDTO) GetUserOk() (*string, bool)` + +GetUserOk returns a tuple with the User field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetUser + +`func (o *WorkspaceDTO) SetUser(v string)` + +SetUser sets User field to given value. + + [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pkg/apiclient/docs/ProjectDirResponse.md b/pkg/apiclient/docs/WorkspaceDirResponse.md similarity index 64% rename from pkg/apiclient/docs/ProjectDirResponse.md rename to pkg/apiclient/docs/WorkspaceDirResponse.md index d2e4c0c2df..6a751c38af 100644 --- a/pkg/apiclient/docs/ProjectDirResponse.md +++ b/pkg/apiclient/docs/WorkspaceDirResponse.md @@ -1,4 +1,4 @@ -# ProjectDirResponse +# WorkspaceDirResponse ## Properties @@ -8,45 +8,45 @@ Name | Type | Description | Notes ## Methods -### NewProjectDirResponse +### NewWorkspaceDirResponse -`func NewProjectDirResponse() *ProjectDirResponse` +`func NewWorkspaceDirResponse() *WorkspaceDirResponse` -NewProjectDirResponse instantiates a new ProjectDirResponse object +NewWorkspaceDirResponse instantiates a new WorkspaceDirResponse object This constructor will assign default values to properties that have it defined, and makes sure properties required by API are set, but the set of arguments will change when the set of required properties is changed -### NewProjectDirResponseWithDefaults +### NewWorkspaceDirResponseWithDefaults -`func NewProjectDirResponseWithDefaults() *ProjectDirResponse` +`func NewWorkspaceDirResponseWithDefaults() *WorkspaceDirResponse` -NewProjectDirResponseWithDefaults instantiates a new ProjectDirResponse object +NewWorkspaceDirResponseWithDefaults instantiates a new WorkspaceDirResponse object This constructor will only assign default values to properties that have it defined, but it doesn't guarantee that properties required by API are set ### GetDir -`func (o *ProjectDirResponse) GetDir() string` +`func (o *WorkspaceDirResponse) GetDir() string` GetDir returns the Dir field if non-nil, zero value otherwise. ### GetDirOk -`func (o *ProjectDirResponse) GetDirOk() (*string, bool)` +`func (o *WorkspaceDirResponse) GetDirOk() (*string, bool)` GetDirOk returns a tuple with the Dir field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. ### SetDir -`func (o *ProjectDirResponse) SetDir(v string)` +`func (o *WorkspaceDirResponse) SetDir(v string)` SetDir sets Dir field to given value. ### HasDir -`func (o *ProjectDirResponse) HasDir() bool` +`func (o *WorkspaceDirResponse) HasDir() bool` HasDir returns a boolean if a field has been set. diff --git a/pkg/apiclient/docs/WorkspaceInfo.md b/pkg/apiclient/docs/WorkspaceInfo.md deleted file mode 100644 index e0468ccaf0..0000000000 --- a/pkg/apiclient/docs/WorkspaceInfo.md +++ /dev/null @@ -1,98 +0,0 @@ -# WorkspaceInfo - -## Properties - -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**Name** | **string** | | -**Projects** | [**[]ProjectInfo**](ProjectInfo.md) | | -**ProviderMetadata** | Pointer to **string** | | [optional] - -## Methods - -### NewWorkspaceInfo - -`func NewWorkspaceInfo(name string, projects []ProjectInfo, ) *WorkspaceInfo` - -NewWorkspaceInfo instantiates a new WorkspaceInfo object -This constructor will assign default values to properties that have it defined, -and makes sure properties required by API are set, but the set of arguments -will change when the set of required properties is changed - -### NewWorkspaceInfoWithDefaults - -`func NewWorkspaceInfoWithDefaults() *WorkspaceInfo` - -NewWorkspaceInfoWithDefaults instantiates a new WorkspaceInfo object -This constructor will only assign default values to properties that have it defined, -but it doesn't guarantee that properties required by API are set - -### GetName - -`func (o *WorkspaceInfo) GetName() string` - -GetName returns the Name field if non-nil, zero value otherwise. - -### GetNameOk - -`func (o *WorkspaceInfo) GetNameOk() (*string, bool)` - -GetNameOk returns a tuple with the Name field if it's non-nil, zero value otherwise -and a boolean to check if the value has been set. - -### SetName - -`func (o *WorkspaceInfo) SetName(v string)` - -SetName sets Name field to given value. - - -### GetProjects - -`func (o *WorkspaceInfo) GetProjects() []ProjectInfo` - -GetProjects returns the Projects field if non-nil, zero value otherwise. - -### GetProjectsOk - -`func (o *WorkspaceInfo) GetProjectsOk() (*[]ProjectInfo, bool)` - -GetProjectsOk returns a tuple with the Projects field if it's non-nil, zero value otherwise -and a boolean to check if the value has been set. - -### SetProjects - -`func (o *WorkspaceInfo) SetProjects(v []ProjectInfo)` - -SetProjects sets Projects field to given value. - - -### GetProviderMetadata - -`func (o *WorkspaceInfo) GetProviderMetadata() string` - -GetProviderMetadata returns the ProviderMetadata field if non-nil, zero value otherwise. - -### GetProviderMetadataOk - -`func (o *WorkspaceInfo) GetProviderMetadataOk() (*string, bool)` - -GetProviderMetadataOk returns a tuple with the ProviderMetadata field if it's non-nil, zero value otherwise -and a boolean to check if the value has been set. - -### SetProviderMetadata - -`func (o *WorkspaceInfo) SetProviderMetadata(v string)` - -SetProviderMetadata sets ProviderMetadata field to given value. - -### HasProviderMetadata - -`func (o *WorkspaceInfo) HasProviderMetadata() bool` - -HasProviderMetadata returns a boolean if a field has been set. - - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/pkg/apiclient/docs/ProjectState.md b/pkg/apiclient/docs/WorkspaceMetadata.md similarity index 55% rename from pkg/apiclient/docs/ProjectState.md rename to pkg/apiclient/docs/WorkspaceMetadata.md index 410b6a949b..afba834445 100644 --- a/pkg/apiclient/docs/ProjectState.md +++ b/pkg/apiclient/docs/WorkspaceMetadata.md @@ -1,4 +1,4 @@ -# ProjectState +# WorkspaceMetadata ## Properties @@ -7,91 +7,112 @@ Name | Type | Description | Notes **GitStatus** | Pointer to [**GitStatus**](GitStatus.md) | | [optional] **UpdatedAt** | **string** | | **Uptime** | **int32** | | +**WorkspaceId** | **string** | | ## Methods -### NewProjectState +### NewWorkspaceMetadata -`func NewProjectState(updatedAt string, uptime int32, ) *ProjectState` +`func NewWorkspaceMetadata(updatedAt string, uptime int32, workspaceId string, ) *WorkspaceMetadata` -NewProjectState instantiates a new ProjectState object +NewWorkspaceMetadata instantiates a new WorkspaceMetadata object This constructor will assign default values to properties that have it defined, and makes sure properties required by API are set, but the set of arguments will change when the set of required properties is changed -### NewProjectStateWithDefaults +### NewWorkspaceMetadataWithDefaults -`func NewProjectStateWithDefaults() *ProjectState` +`func NewWorkspaceMetadataWithDefaults() *WorkspaceMetadata` -NewProjectStateWithDefaults instantiates a new ProjectState object +NewWorkspaceMetadataWithDefaults instantiates a new WorkspaceMetadata object This constructor will only assign default values to properties that have it defined, but it doesn't guarantee that properties required by API are set ### GetGitStatus -`func (o *ProjectState) GetGitStatus() GitStatus` +`func (o *WorkspaceMetadata) GetGitStatus() GitStatus` GetGitStatus returns the GitStatus field if non-nil, zero value otherwise. ### GetGitStatusOk -`func (o *ProjectState) GetGitStatusOk() (*GitStatus, bool)` +`func (o *WorkspaceMetadata) GetGitStatusOk() (*GitStatus, bool)` GetGitStatusOk returns a tuple with the GitStatus field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. ### SetGitStatus -`func (o *ProjectState) SetGitStatus(v GitStatus)` +`func (o *WorkspaceMetadata) SetGitStatus(v GitStatus)` SetGitStatus sets GitStatus field to given value. ### HasGitStatus -`func (o *ProjectState) HasGitStatus() bool` +`func (o *WorkspaceMetadata) HasGitStatus() bool` HasGitStatus returns a boolean if a field has been set. ### GetUpdatedAt -`func (o *ProjectState) GetUpdatedAt() string` +`func (o *WorkspaceMetadata) GetUpdatedAt() string` GetUpdatedAt returns the UpdatedAt field if non-nil, zero value otherwise. ### GetUpdatedAtOk -`func (o *ProjectState) GetUpdatedAtOk() (*string, bool)` +`func (o *WorkspaceMetadata) GetUpdatedAtOk() (*string, bool)` GetUpdatedAtOk returns a tuple with the UpdatedAt field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. ### SetUpdatedAt -`func (o *ProjectState) SetUpdatedAt(v string)` +`func (o *WorkspaceMetadata) SetUpdatedAt(v string)` SetUpdatedAt sets UpdatedAt field to given value. ### GetUptime -`func (o *ProjectState) GetUptime() int32` +`func (o *WorkspaceMetadata) GetUptime() int32` GetUptime returns the Uptime field if non-nil, zero value otherwise. ### GetUptimeOk -`func (o *ProjectState) GetUptimeOk() (*int32, bool)` +`func (o *WorkspaceMetadata) GetUptimeOk() (*int32, bool)` GetUptimeOk returns a tuple with the Uptime field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. ### SetUptime -`func (o *ProjectState) SetUptime(v int32)` +`func (o *WorkspaceMetadata) SetUptime(v int32)` SetUptime sets Uptime field to given value. +### GetWorkspaceId + +`func (o *WorkspaceMetadata) GetWorkspaceId() string` + +GetWorkspaceId returns the WorkspaceId field if non-nil, zero value otherwise. + +### GetWorkspaceIdOk + +`func (o *WorkspaceMetadata) GetWorkspaceIdOk() (*string, bool)` + +GetWorkspaceIdOk returns a tuple with the WorkspaceId field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetWorkspaceId + +`func (o *WorkspaceMetadata) SetWorkspaceId(v string)` + +SetWorkspaceId sets WorkspaceId field to given value. + + [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pkg/apiclient/docs/ProjectConfig.md b/pkg/apiclient/docs/WorkspaceTemplate.md similarity index 61% rename from pkg/apiclient/docs/ProjectConfig.md rename to pkg/apiclient/docs/WorkspaceTemplate.md index 4c211bd2fa..45b72cc64b 100644 --- a/pkg/apiclient/docs/ProjectConfig.md +++ b/pkg/apiclient/docs/WorkspaceTemplate.md @@ -1,4 +1,4 @@ -# ProjectConfig +# WorkspaceTemplate ## Properties @@ -9,6 +9,7 @@ Name | Type | Description | Notes **EnvVars** | **map[string]string** | | **GitProviderConfigId** | Pointer to **string** | | [optional] **Image** | **string** | | +**Labels** | **map[string]string** | | **Name** | **string** | | **Prebuilds** | Pointer to [**[]PrebuildConfig**](PrebuildConfig.md) | | [optional] **RepositoryUrl** | **string** | | @@ -16,214 +17,234 @@ Name | Type | Description | Notes ## Methods -### NewProjectConfig +### NewWorkspaceTemplate -`func NewProjectConfig(default_ bool, envVars map[string]string, image string, name string, repositoryUrl string, user string, ) *ProjectConfig` +`func NewWorkspaceTemplate(default_ bool, envVars map[string]string, image string, labels map[string]string, name string, repositoryUrl string, user string, ) *WorkspaceTemplate` -NewProjectConfig instantiates a new ProjectConfig object +NewWorkspaceTemplate instantiates a new WorkspaceTemplate object This constructor will assign default values to properties that have it defined, and makes sure properties required by API are set, but the set of arguments will change when the set of required properties is changed -### NewProjectConfigWithDefaults +### NewWorkspaceTemplateWithDefaults -`func NewProjectConfigWithDefaults() *ProjectConfig` +`func NewWorkspaceTemplateWithDefaults() *WorkspaceTemplate` -NewProjectConfigWithDefaults instantiates a new ProjectConfig object +NewWorkspaceTemplateWithDefaults instantiates a new WorkspaceTemplate object This constructor will only assign default values to properties that have it defined, but it doesn't guarantee that properties required by API are set ### GetBuildConfig -`func (o *ProjectConfig) GetBuildConfig() BuildConfig` +`func (o *WorkspaceTemplate) GetBuildConfig() BuildConfig` GetBuildConfig returns the BuildConfig field if non-nil, zero value otherwise. ### GetBuildConfigOk -`func (o *ProjectConfig) GetBuildConfigOk() (*BuildConfig, bool)` +`func (o *WorkspaceTemplate) GetBuildConfigOk() (*BuildConfig, bool)` GetBuildConfigOk returns a tuple with the BuildConfig field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. ### SetBuildConfig -`func (o *ProjectConfig) SetBuildConfig(v BuildConfig)` +`func (o *WorkspaceTemplate) SetBuildConfig(v BuildConfig)` SetBuildConfig sets BuildConfig field to given value. ### HasBuildConfig -`func (o *ProjectConfig) HasBuildConfig() bool` +`func (o *WorkspaceTemplate) HasBuildConfig() bool` HasBuildConfig returns a boolean if a field has been set. ### GetDefault -`func (o *ProjectConfig) GetDefault() bool` +`func (o *WorkspaceTemplate) GetDefault() bool` GetDefault returns the Default field if non-nil, zero value otherwise. ### GetDefaultOk -`func (o *ProjectConfig) GetDefaultOk() (*bool, bool)` +`func (o *WorkspaceTemplate) GetDefaultOk() (*bool, bool)` GetDefaultOk returns a tuple with the Default field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. ### SetDefault -`func (o *ProjectConfig) SetDefault(v bool)` +`func (o *WorkspaceTemplate) SetDefault(v bool)` SetDefault sets Default field to given value. ### GetEnvVars -`func (o *ProjectConfig) GetEnvVars() map[string]string` +`func (o *WorkspaceTemplate) GetEnvVars() map[string]string` GetEnvVars returns the EnvVars field if non-nil, zero value otherwise. ### GetEnvVarsOk -`func (o *ProjectConfig) GetEnvVarsOk() (*map[string]string, bool)` +`func (o *WorkspaceTemplate) GetEnvVarsOk() (*map[string]string, bool)` GetEnvVarsOk returns a tuple with the EnvVars field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. ### SetEnvVars -`func (o *ProjectConfig) SetEnvVars(v map[string]string)` +`func (o *WorkspaceTemplate) SetEnvVars(v map[string]string)` SetEnvVars sets EnvVars field to given value. ### GetGitProviderConfigId -`func (o *ProjectConfig) GetGitProviderConfigId() string` +`func (o *WorkspaceTemplate) GetGitProviderConfigId() string` GetGitProviderConfigId returns the GitProviderConfigId field if non-nil, zero value otherwise. ### GetGitProviderConfigIdOk -`func (o *ProjectConfig) GetGitProviderConfigIdOk() (*string, bool)` +`func (o *WorkspaceTemplate) GetGitProviderConfigIdOk() (*string, bool)` GetGitProviderConfigIdOk returns a tuple with the GitProviderConfigId field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. ### SetGitProviderConfigId -`func (o *ProjectConfig) SetGitProviderConfigId(v string)` +`func (o *WorkspaceTemplate) SetGitProviderConfigId(v string)` SetGitProviderConfigId sets GitProviderConfigId field to given value. ### HasGitProviderConfigId -`func (o *ProjectConfig) HasGitProviderConfigId() bool` +`func (o *WorkspaceTemplate) HasGitProviderConfigId() bool` HasGitProviderConfigId returns a boolean if a field has been set. ### GetImage -`func (o *ProjectConfig) GetImage() string` +`func (o *WorkspaceTemplate) GetImage() string` GetImage returns the Image field if non-nil, zero value otherwise. ### GetImageOk -`func (o *ProjectConfig) GetImageOk() (*string, bool)` +`func (o *WorkspaceTemplate) GetImageOk() (*string, bool)` GetImageOk returns a tuple with the Image field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. ### SetImage -`func (o *ProjectConfig) SetImage(v string)` +`func (o *WorkspaceTemplate) SetImage(v string)` SetImage sets Image field to given value. +### GetLabels + +`func (o *WorkspaceTemplate) GetLabels() map[string]string` + +GetLabels returns the Labels field if non-nil, zero value otherwise. + +### GetLabelsOk + +`func (o *WorkspaceTemplate) GetLabelsOk() (*map[string]string, bool)` + +GetLabelsOk returns a tuple with the Labels field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetLabels + +`func (o *WorkspaceTemplate) SetLabels(v map[string]string)` + +SetLabels sets Labels field to given value. + + ### GetName -`func (o *ProjectConfig) GetName() string` +`func (o *WorkspaceTemplate) GetName() string` GetName returns the Name field if non-nil, zero value otherwise. ### GetNameOk -`func (o *ProjectConfig) GetNameOk() (*string, bool)` +`func (o *WorkspaceTemplate) GetNameOk() (*string, bool)` GetNameOk returns a tuple with the Name field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. ### SetName -`func (o *ProjectConfig) SetName(v string)` +`func (o *WorkspaceTemplate) SetName(v string)` SetName sets Name field to given value. ### GetPrebuilds -`func (o *ProjectConfig) GetPrebuilds() []PrebuildConfig` +`func (o *WorkspaceTemplate) GetPrebuilds() []PrebuildConfig` GetPrebuilds returns the Prebuilds field if non-nil, zero value otherwise. ### GetPrebuildsOk -`func (o *ProjectConfig) GetPrebuildsOk() (*[]PrebuildConfig, bool)` +`func (o *WorkspaceTemplate) GetPrebuildsOk() (*[]PrebuildConfig, bool)` GetPrebuildsOk returns a tuple with the Prebuilds field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. ### SetPrebuilds -`func (o *ProjectConfig) SetPrebuilds(v []PrebuildConfig)` +`func (o *WorkspaceTemplate) SetPrebuilds(v []PrebuildConfig)` SetPrebuilds sets Prebuilds field to given value. ### HasPrebuilds -`func (o *ProjectConfig) HasPrebuilds() bool` +`func (o *WorkspaceTemplate) HasPrebuilds() bool` HasPrebuilds returns a boolean if a field has been set. ### GetRepositoryUrl -`func (o *ProjectConfig) GetRepositoryUrl() string` +`func (o *WorkspaceTemplate) GetRepositoryUrl() string` GetRepositoryUrl returns the RepositoryUrl field if non-nil, zero value otherwise. ### GetRepositoryUrlOk -`func (o *ProjectConfig) GetRepositoryUrlOk() (*string, bool)` +`func (o *WorkspaceTemplate) GetRepositoryUrlOk() (*string, bool)` GetRepositoryUrlOk returns a tuple with the RepositoryUrl field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. ### SetRepositoryUrl -`func (o *ProjectConfig) SetRepositoryUrl(v string)` +`func (o *WorkspaceTemplate) SetRepositoryUrl(v string)` SetRepositoryUrl sets RepositoryUrl field to given value. ### GetUser -`func (o *ProjectConfig) GetUser() string` +`func (o *WorkspaceTemplate) GetUser() string` GetUser returns the User field if non-nil, zero value otherwise. ### GetUserOk -`func (o *ProjectConfig) GetUserOk() (*string, bool)` +`func (o *WorkspaceTemplate) GetUserOk() (*string, bool)` GetUserOk returns a tuple with the User field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. ### SetUser -`func (o *ProjectConfig) SetUser(v string)` +`func (o *WorkspaceTemplate) SetUser(v string)` SetUser sets User field to given value. diff --git a/pkg/apiclient/docs/ProjectConfigAPI.md b/pkg/apiclient/docs/WorkspaceTemplateAPI.md similarity index 55% rename from pkg/apiclient/docs/ProjectConfigAPI.md rename to pkg/apiclient/docs/WorkspaceTemplateAPI.md index f3b095ae9b..23d8bb1025 100644 --- a/pkg/apiclient/docs/ProjectConfigAPI.md +++ b/pkg/apiclient/docs/WorkspaceTemplateAPI.md @@ -1,23 +1,23 @@ -# \ProjectConfigAPI +# \WorkspaceTemplateAPI All URIs are relative to *http://localhost:3986* Method | HTTP request | Description ------------- | ------------- | ------------- -[**DeleteProjectConfig**](ProjectConfigAPI.md#DeleteProjectConfig) | **Delete** /project-config/{configName} | Delete project config data -[**GetDefaultProjectConfig**](ProjectConfigAPI.md#GetDefaultProjectConfig) | **Get** /project-config/default/{gitUrl} | Get project configs by git url -[**GetProjectConfig**](ProjectConfigAPI.md#GetProjectConfig) | **Get** /project-config/{configName} | Get project config data -[**ListProjectConfigs**](ProjectConfigAPI.md#ListProjectConfigs) | **Get** /project-config | List project configs -[**SetDefaultProjectConfig**](ProjectConfigAPI.md#SetDefaultProjectConfig) | **Patch** /project-config/{configName}/set-default | Set project config to default -[**SetProjectConfig**](ProjectConfigAPI.md#SetProjectConfig) | **Put** /project-config | Set project config data +[**DeleteWorkspaceTemplate**](WorkspaceTemplateAPI.md#DeleteWorkspaceTemplate) | **Delete** /workspace-template/{templateName} | Delete workspace template data +[**FindWorkspaceTemplate**](WorkspaceTemplateAPI.md#FindWorkspaceTemplate) | **Get** /workspace-template/{templateName} | Find a workspace template +[**GetDefaultWorkspaceTemplate**](WorkspaceTemplateAPI.md#GetDefaultWorkspaceTemplate) | **Get** /workspace-template/default/{gitUrl} | Get default workspace templates by git url +[**ListWorkspaceTemplates**](WorkspaceTemplateAPI.md#ListWorkspaceTemplates) | **Get** /workspace-template | List workspace templates +[**SaveWorkspaceTemplate**](WorkspaceTemplateAPI.md#SaveWorkspaceTemplate) | **Put** /workspace-template | Set workspace template data +[**SetDefaultWorkspaceTemplate**](WorkspaceTemplateAPI.md#SetDefaultWorkspaceTemplate) | **Patch** /workspace-template/{templateName}/set-default | Set workspace template to default -## DeleteProjectConfig +## DeleteWorkspaceTemplate -> DeleteProjectConfig(ctx, configName).Force(force).Execute() +> DeleteWorkspaceTemplate(ctx, templateName).Force(force).Execute() -Delete project config data +Delete workspace template data @@ -34,14 +34,14 @@ import ( ) func main() { - configName := "configName_example" // string | Config name + templateName := "templateName_example" // string | Template name force := true // bool | Force (optional) configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - r, err := apiClient.ProjectConfigAPI.DeleteProjectConfig(context.Background(), configName).Force(force).Execute() + r, err := apiClient.WorkspaceTemplateAPI.DeleteWorkspaceTemplate(context.Background(), templateName).Force(force).Execute() if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `ProjectConfigAPI.DeleteProjectConfig``: %v\n", err) + fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceTemplateAPI.DeleteWorkspaceTemplate``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) } } @@ -53,11 +53,11 @@ func main() { Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. -**configName** | **string** | Config name | +**templateName** | **string** | Template name | ### Other Parameters -Other parameters are passed through a pointer to a apiDeleteProjectConfigRequest struct via the builder pattern +Other parameters are passed through a pointer to a apiDeleteWorkspaceTemplateRequest struct via the builder pattern Name | Type | Description | Notes @@ -83,11 +83,11 @@ Name | Type | Description | Notes [[Back to README]](../README.md) -## GetDefaultProjectConfig +## FindWorkspaceTemplate -> ProjectConfig GetDefaultProjectConfig(ctx, gitUrl).Execute() +> WorkspaceTemplate FindWorkspaceTemplate(ctx, templateName).Execute() -Get project configs by git url +Find a workspace template @@ -104,17 +104,17 @@ import ( ) func main() { - gitUrl := "gitUrl_example" // string | Git URL + templateName := "templateName_example" // string | Template name configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.ProjectConfigAPI.GetDefaultProjectConfig(context.Background(), gitUrl).Execute() + resp, r, err := apiClient.WorkspaceTemplateAPI.FindWorkspaceTemplate(context.Background(), templateName).Execute() if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `ProjectConfigAPI.GetDefaultProjectConfig``: %v\n", err) + fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceTemplateAPI.FindWorkspaceTemplate``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) } - // response from `GetDefaultProjectConfig`: ProjectConfig - fmt.Fprintf(os.Stdout, "Response from `ProjectConfigAPI.GetDefaultProjectConfig`: %v\n", resp) + // response from `FindWorkspaceTemplate`: WorkspaceTemplate + fmt.Fprintf(os.Stdout, "Response from `WorkspaceTemplateAPI.FindWorkspaceTemplate`: %v\n", resp) } ``` @@ -124,11 +124,11 @@ func main() { Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. -**gitUrl** | **string** | Git URL | +**templateName** | **string** | Template name | ### Other Parameters -Other parameters are passed through a pointer to a apiGetDefaultProjectConfigRequest struct via the builder pattern +Other parameters are passed through a pointer to a apiFindWorkspaceTemplateRequest struct via the builder pattern Name | Type | Description | Notes @@ -137,7 +137,7 @@ Name | Type | Description | Notes ### Return type -[**ProjectConfig**](ProjectConfig.md) +[**WorkspaceTemplate**](WorkspaceTemplate.md) ### Authorization @@ -146,18 +146,18 @@ Name | Type | Description | Notes ### HTTP request headers - **Content-Type**: Not defined -- **Accept**: application/json +- **Accept**: */* [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) -## GetProjectConfig +## GetDefaultWorkspaceTemplate -> ProjectConfig GetProjectConfig(ctx, configName).Execute() +> WorkspaceTemplate GetDefaultWorkspaceTemplate(ctx, gitUrl).Execute() -Get project config data +Get default workspace templates by git url @@ -174,17 +174,17 @@ import ( ) func main() { - configName := "configName_example" // string | Config name + gitUrl := "gitUrl_example" // string | Git URL configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.ProjectConfigAPI.GetProjectConfig(context.Background(), configName).Execute() + resp, r, err := apiClient.WorkspaceTemplateAPI.GetDefaultWorkspaceTemplate(context.Background(), gitUrl).Execute() if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `ProjectConfigAPI.GetProjectConfig``: %v\n", err) + fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceTemplateAPI.GetDefaultWorkspaceTemplate``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) } - // response from `GetProjectConfig`: ProjectConfig - fmt.Fprintf(os.Stdout, "Response from `ProjectConfigAPI.GetProjectConfig`: %v\n", resp) + // response from `GetDefaultWorkspaceTemplate`: WorkspaceTemplate + fmt.Fprintf(os.Stdout, "Response from `WorkspaceTemplateAPI.GetDefaultWorkspaceTemplate`: %v\n", resp) } ``` @@ -194,11 +194,11 @@ func main() { Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. -**configName** | **string** | Config name | +**gitUrl** | **string** | Git URL | ### Other Parameters -Other parameters are passed through a pointer to a apiGetProjectConfigRequest struct via the builder pattern +Other parameters are passed through a pointer to a apiGetDefaultWorkspaceTemplateRequest struct via the builder pattern Name | Type | Description | Notes @@ -207,7 +207,7 @@ Name | Type | Description | Notes ### Return type -[**ProjectConfig**](ProjectConfig.md) +[**WorkspaceTemplate**](WorkspaceTemplate.md) ### Authorization @@ -216,18 +216,18 @@ Name | Type | Description | Notes ### HTTP request headers - **Content-Type**: Not defined -- **Accept**: */* +- **Accept**: application/json [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) -## ListProjectConfigs +## ListWorkspaceTemplates -> []ProjectConfig ListProjectConfigs(ctx).Execute() +> []WorkspaceTemplate ListWorkspaceTemplates(ctx).Execute() -List project configs +List workspace templates @@ -247,13 +247,13 @@ func main() { configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.ProjectConfigAPI.ListProjectConfigs(context.Background()).Execute() + resp, r, err := apiClient.WorkspaceTemplateAPI.ListWorkspaceTemplates(context.Background()).Execute() if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `ProjectConfigAPI.ListProjectConfigs``: %v\n", err) + fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceTemplateAPI.ListWorkspaceTemplates``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) } - // response from `ListProjectConfigs`: []ProjectConfig - fmt.Fprintf(os.Stdout, "Response from `ProjectConfigAPI.ListProjectConfigs`: %v\n", resp) + // response from `ListWorkspaceTemplates`: []WorkspaceTemplate + fmt.Fprintf(os.Stdout, "Response from `WorkspaceTemplateAPI.ListWorkspaceTemplates`: %v\n", resp) } ``` @@ -263,12 +263,12 @@ This endpoint does not need any parameter. ### Other Parameters -Other parameters are passed through a pointer to a apiListProjectConfigsRequest struct via the builder pattern +Other parameters are passed through a pointer to a apiListWorkspaceTemplatesRequest struct via the builder pattern ### Return type -[**[]ProjectConfig**](ProjectConfig.md) +[**[]WorkspaceTemplate**](WorkspaceTemplate.md) ### Authorization @@ -284,11 +284,11 @@ Other parameters are passed through a pointer to a apiListProjectConfigsRequest [[Back to README]](../README.md) -## SetDefaultProjectConfig +## SaveWorkspaceTemplate -> SetDefaultProjectConfig(ctx, configName).Execute() +> SaveWorkspaceTemplate(ctx).WorkspaceTemplate(workspaceTemplate).Execute() -Set project config to default +Set workspace template data @@ -305,13 +305,13 @@ import ( ) func main() { - configName := "configName_example" // string | Config name + workspaceTemplate := *openapiclient.NewCreateWorkspaceTemplateDTO(map[string]string{"key": "Inner_example"}, "Name_example", "RepositoryUrl_example") // CreateWorkspaceTemplateDTO | Workspace template configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - r, err := apiClient.ProjectConfigAPI.SetDefaultProjectConfig(context.Background(), configName).Execute() + r, err := apiClient.WorkspaceTemplateAPI.SaveWorkspaceTemplate(context.Background()).WorkspaceTemplate(workspaceTemplate).Execute() if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `ProjectConfigAPI.SetDefaultProjectConfig``: %v\n", err) + fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceTemplateAPI.SaveWorkspaceTemplate``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) } } @@ -320,19 +320,15 @@ func main() { ### Path Parameters -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- -**ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. -**configName** | **string** | Config name | ### Other Parameters -Other parameters are passed through a pointer to a apiSetDefaultProjectConfigRequest struct via the builder pattern +Other parameters are passed through a pointer to a apiSaveWorkspaceTemplateRequest struct via the builder pattern Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - + **workspaceTemplate** | [**CreateWorkspaceTemplateDTO**](CreateWorkspaceTemplateDTO.md) | Workspace template | ### Return type @@ -344,7 +340,7 @@ Name | Type | Description | Notes ### HTTP request headers -- **Content-Type**: Not defined +- **Content-Type**: application/json - **Accept**: Not defined [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) @@ -352,11 +348,11 @@ Name | Type | Description | Notes [[Back to README]](../README.md) -## SetProjectConfig +## SetDefaultWorkspaceTemplate -> SetProjectConfig(ctx).ProjectConfig(projectConfig).Execute() +> SetDefaultWorkspaceTemplate(ctx, templateName).Execute() -Set project config data +Set workspace template to default @@ -373,13 +369,13 @@ import ( ) func main() { - projectConfig := *openapiclient.NewCreateProjectConfigDTO(map[string]string{"key": "Inner_example"}, "Name_example", "RepositoryUrl_example") // CreateProjectConfigDTO | Project config + templateName := "templateName_example" // string | Template name configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - r, err := apiClient.ProjectConfigAPI.SetProjectConfig(context.Background()).ProjectConfig(projectConfig).Execute() + r, err := apiClient.WorkspaceTemplateAPI.SetDefaultWorkspaceTemplate(context.Background(), templateName).Execute() if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `ProjectConfigAPI.SetProjectConfig``: %v\n", err) + fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceTemplateAPI.SetDefaultWorkspaceTemplate``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) } } @@ -388,15 +384,19 @@ func main() { ### Path Parameters +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- +**ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. +**templateName** | **string** | Template name | ### Other Parameters -Other parameters are passed through a pointer to a apiSetProjectConfigRequest struct via the builder pattern +Other parameters are passed through a pointer to a apiSetDefaultWorkspaceTemplateRequest struct via the builder pattern Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - **projectConfig** | [**CreateProjectConfigDTO**](CreateProjectConfigDTO.md) | Project config | + ### Return type @@ -408,7 +408,7 @@ Name | Type | Description | Notes ### HTTP request headers -- **Content-Type**: application/json +- **Content-Type**: Not defined - **Accept**: Not defined [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) diff --git a/pkg/apiclient/docs/WorkspaceToolboxAPI.md b/pkg/apiclient/docs/WorkspaceToolboxAPI.md index 68eed3396c..86974ca868 100644 --- a/pkg/apiclient/docs/WorkspaceToolboxAPI.md +++ b/pkg/apiclient/docs/WorkspaceToolboxAPI.md @@ -4,46 +4,46 @@ All URIs are relative to *http://localhost:3986* Method | HTTP request | Description ------------- | ------------- | ------------- -[**CreateSession**](WorkspaceToolboxAPI.md#CreateSession) | **Post** /workspace/{workspaceId}/{projectId}/toolbox/process/session | Create exec session -[**DeleteSession**](WorkspaceToolboxAPI.md#DeleteSession) | **Delete** /workspace/{workspaceId}/{projectId}/toolbox/process/session/{sessionId} | Delete session -[**FsCreateFolder**](WorkspaceToolboxAPI.md#FsCreateFolder) | **Post** /workspace/{workspaceId}/{projectId}/toolbox/files/folder | Create folder -[**FsDeleteFile**](WorkspaceToolboxAPI.md#FsDeleteFile) | **Delete** /workspace/{workspaceId}/{projectId}/toolbox/files | Delete file -[**FsDownloadFile**](WorkspaceToolboxAPI.md#FsDownloadFile) | **Get** /workspace/{workspaceId}/{projectId}/toolbox/files/download | Download file -[**FsFindInFiles**](WorkspaceToolboxAPI.md#FsFindInFiles) | **Get** /workspace/{workspaceId}/{projectId}/toolbox/files/find | Search for text/pattern in files -[**FsGetFileDetails**](WorkspaceToolboxAPI.md#FsGetFileDetails) | **Get** /workspace/{workspaceId}/{projectId}/toolbox/files/info | Get file info -[**FsListFiles**](WorkspaceToolboxAPI.md#FsListFiles) | **Get** /workspace/{workspaceId}/{projectId}/toolbox/files | List files -[**FsMoveFile**](WorkspaceToolboxAPI.md#FsMoveFile) | **Post** /workspace/{workspaceId}/{projectId}/toolbox/files/move | Create folder -[**FsReplaceInFiles**](WorkspaceToolboxAPI.md#FsReplaceInFiles) | **Post** /workspace/{workspaceId}/{projectId}/toolbox/files/replace | Repleace text/pattern in files -[**FsSearchFiles**](WorkspaceToolboxAPI.md#FsSearchFiles) | **Get** /workspace/{workspaceId}/{projectId}/toolbox/files/search | Search for files -[**FsSetFilePermissions**](WorkspaceToolboxAPI.md#FsSetFilePermissions) | **Post** /workspace/{workspaceId}/{projectId}/toolbox/files/permissions | Set file owner/group/permissions -[**FsUploadFile**](WorkspaceToolboxAPI.md#FsUploadFile) | **Post** /workspace/{workspaceId}/{projectId}/toolbox/files/upload | Upload file -[**GetProjectDir**](WorkspaceToolboxAPI.md#GetProjectDir) | **Get** /workspace/{workspaceId}/{projectId}/toolbox/project-dir | Get project dir -[**GetSessionCommandLogs**](WorkspaceToolboxAPI.md#GetSessionCommandLogs) | **Get** /workspace/{workspaceId}/{projectId}/toolbox/process/session/{sessionId}/command/{commandId}/logs | Get session command logs -[**GitAddFiles**](WorkspaceToolboxAPI.md#GitAddFiles) | **Post** /workspace/{workspaceId}/{projectId}/toolbox/git/add | Add files -[**GitBranchList**](WorkspaceToolboxAPI.md#GitBranchList) | **Get** /workspace/{workspaceId}/{projectId}/toolbox/git/branches | Get branch list -[**GitCloneRepository**](WorkspaceToolboxAPI.md#GitCloneRepository) | **Post** /workspace/{workspaceId}/{projectId}/toolbox/git/clone | Clone git repository -[**GitCommitChanges**](WorkspaceToolboxAPI.md#GitCommitChanges) | **Post** /workspace/{workspaceId}/{projectId}/toolbox/git/commit | Commit changes -[**GitCommitHistory**](WorkspaceToolboxAPI.md#GitCommitHistory) | **Get** /workspace/{workspaceId}/{projectId}/toolbox/git/history | Get commit history -[**GitCreateBranch**](WorkspaceToolboxAPI.md#GitCreateBranch) | **Post** /workspace/{workspaceId}/{projectId}/toolbox/git/branches | Create branch -[**GitGitStatus**](WorkspaceToolboxAPI.md#GitGitStatus) | **Get** /workspace/{workspaceId}/{projectId}/toolbox/git/status | Get git status -[**GitPullChanges**](WorkspaceToolboxAPI.md#GitPullChanges) | **Post** /workspace/{workspaceId}/{projectId}/toolbox/git/pull | Pull changes -[**GitPushChanges**](WorkspaceToolboxAPI.md#GitPushChanges) | **Post** /workspace/{workspaceId}/{projectId}/toolbox/git/push | Push changes -[**ListSessions**](WorkspaceToolboxAPI.md#ListSessions) | **Get** /workspace/{workspaceId}/{projectId}/toolbox/process/session | List sessions -[**LspCompletions**](WorkspaceToolboxAPI.md#LspCompletions) | **Post** /workspace/{workspaceId}/{projectId}/toolbox/lsp/completions | Get Lsp Completions -[**LspDidClose**](WorkspaceToolboxAPI.md#LspDidClose) | **Post** /workspace/{workspaceId}/{projectId}/toolbox/lsp/did-close | Call Lsp DidClose -[**LspDidOpen**](WorkspaceToolboxAPI.md#LspDidOpen) | **Post** /workspace/{workspaceId}/{projectId}/toolbox/lsp/did-open | Call Lsp DidOpen -[**LspDocumentSymbols**](WorkspaceToolboxAPI.md#LspDocumentSymbols) | **Get** /workspace/{workspaceId}/{projectId}/toolbox/lsp/document-symbols | Call Lsp DocumentSymbols -[**LspStart**](WorkspaceToolboxAPI.md#LspStart) | **Post** /workspace/{workspaceId}/{projectId}/toolbox/lsp/start | Start Lsp server -[**LspStop**](WorkspaceToolboxAPI.md#LspStop) | **Post** /workspace/{workspaceId}/{projectId}/toolbox/lsp/stop | Stop Lsp server -[**LspWorkspaceSymbols**](WorkspaceToolboxAPI.md#LspWorkspaceSymbols) | **Get** /workspace/{workspaceId}/{projectId}/toolbox/lsp/workspace-symbols | Call Lsp WorkspaceSymbols -[**ProcessExecuteCommand**](WorkspaceToolboxAPI.md#ProcessExecuteCommand) | **Post** /workspace/{workspaceId}/{projectId}/toolbox/process/execute | Execute command -[**SessionExecuteCommand**](WorkspaceToolboxAPI.md#SessionExecuteCommand) | **Post** /workspace/{workspaceId}/{projectId}/toolbox/process/session/{sessionId}/exec | Execute command in session +[**CreateSession**](WorkspaceToolboxAPI.md#CreateSession) | **Post** /workspace/{workspaceId}/toolbox/process/session | Create exec session +[**DeleteSession**](WorkspaceToolboxAPI.md#DeleteSession) | **Delete** /workspace/{workspaceId}/toolbox/process/session/{sessionId} | Delete session +[**FsCreateFolder**](WorkspaceToolboxAPI.md#FsCreateFolder) | **Post** /workspace/{workspaceId}/toolbox/files/folder | Create folder +[**FsDeleteFile**](WorkspaceToolboxAPI.md#FsDeleteFile) | **Delete** /workspace/{workspaceId}/toolbox/files | Delete file +[**FsDownloadFile**](WorkspaceToolboxAPI.md#FsDownloadFile) | **Get** /workspace/{workspaceId}/toolbox/files/download | Download file +[**FsFindInFiles**](WorkspaceToolboxAPI.md#FsFindInFiles) | **Get** /workspace/{workspaceId}/toolbox/files/find | Search for text/pattern in files +[**FsGetFileDetails**](WorkspaceToolboxAPI.md#FsGetFileDetails) | **Get** /workspace/{workspaceId}/toolbox/files/info | Get file info +[**FsListFiles**](WorkspaceToolboxAPI.md#FsListFiles) | **Get** /workspace/{workspaceId}/toolbox/files | List files +[**FsMoveFile**](WorkspaceToolboxAPI.md#FsMoveFile) | **Post** /workspace/{workspaceId}/toolbox/files/move | Create folder +[**FsReplaceInFiles**](WorkspaceToolboxAPI.md#FsReplaceInFiles) | **Post** /workspace/{workspaceId}/toolbox/files/replace | Repleace text/pattern in files +[**FsSearchFiles**](WorkspaceToolboxAPI.md#FsSearchFiles) | **Get** /workspace/{workspaceId}/toolbox/files/search | Search for files +[**FsSetFilePermissions**](WorkspaceToolboxAPI.md#FsSetFilePermissions) | **Post** /workspace/{workspaceId}/toolbox/files/permissions | Set file owner/group/permissions +[**FsUploadFile**](WorkspaceToolboxAPI.md#FsUploadFile) | **Post** /workspace/{workspaceId}/toolbox/files/upload | Upload file +[**GetSessionCommandLogs**](WorkspaceToolboxAPI.md#GetSessionCommandLogs) | **Get** /workspace/{workspaceId}/toolbox/process/session/{sessionId}/command/{commandId}/logs | Get session command logs +[**GetWorkspaceDir**](WorkspaceToolboxAPI.md#GetWorkspaceDir) | **Get** /workspace/{workspaceId}/toolbox/workspace-dir | Get workspace dir +[**GitAddFiles**](WorkspaceToolboxAPI.md#GitAddFiles) | **Post** /workspace/{workspaceId}/toolbox/git/add | Add files +[**GitBranchList**](WorkspaceToolboxAPI.md#GitBranchList) | **Get** /workspace/{workspaceId}/toolbox/git/branches | Get branch list +[**GitCloneRepository**](WorkspaceToolboxAPI.md#GitCloneRepository) | **Post** /workspace/{workspaceId}/toolbox/git/clone | Clone git repository +[**GitCommitChanges**](WorkspaceToolboxAPI.md#GitCommitChanges) | **Post** /workspace/{workspaceId}/toolbox/git/commit | Commit changes +[**GitCommitHistory**](WorkspaceToolboxAPI.md#GitCommitHistory) | **Get** /workspace/{workspaceId}/toolbox/git/history | Get commit history +[**GitCreateBranch**](WorkspaceToolboxAPI.md#GitCreateBranch) | **Post** /workspace/{workspaceId}/toolbox/git/branches | Create branch +[**GitGitStatus**](WorkspaceToolboxAPI.md#GitGitStatus) | **Get** /workspace/{workspaceId}/toolbox/git/status | Get git status +[**GitPullChanges**](WorkspaceToolboxAPI.md#GitPullChanges) | **Post** /workspace/{workspaceId}/toolbox/git/pull | Pull changes +[**GitPushChanges**](WorkspaceToolboxAPI.md#GitPushChanges) | **Post** /workspace/{workspaceId}/toolbox/git/push | Push changes +[**ListSessions**](WorkspaceToolboxAPI.md#ListSessions) | **Get** /workspace/{workspaceId}/toolbox/process/session | List sessions +[**LspCompletions**](WorkspaceToolboxAPI.md#LspCompletions) | **Post** /workspace/{workspaceId}/toolbox/lsp/completions | Get Lsp Completions +[**LspDidClose**](WorkspaceToolboxAPI.md#LspDidClose) | **Post** /workspace/{workspaceId}/toolbox/lsp/did-close | Call Lsp DidClose +[**LspDidOpen**](WorkspaceToolboxAPI.md#LspDidOpen) | **Post** /workspace/{workspaceId}/toolbox/lsp/did-open | Call Lsp DidOpen +[**LspDocumentSymbols**](WorkspaceToolboxAPI.md#LspDocumentSymbols) | **Get** /workspace/{workspaceId}/toolbox/lsp/document-symbols | Call Lsp DocumentSymbols +[**LspStart**](WorkspaceToolboxAPI.md#LspStart) | **Post** /workspace/{workspaceId}/toolbox/lsp/start | Start Lsp server +[**LspStop**](WorkspaceToolboxAPI.md#LspStop) | **Post** /workspace/{workspaceId}/toolbox/lsp/stop | Stop Lsp server +[**LspWorkspaceSymbols**](WorkspaceToolboxAPI.md#LspWorkspaceSymbols) | **Get** /workspace/{workspaceId}/toolbox/lsp/workspace-symbols | Call Lsp WorkspaceSymbols +[**ProcessExecuteCommand**](WorkspaceToolboxAPI.md#ProcessExecuteCommand) | **Post** /workspace/{workspaceId}/toolbox/process/execute | Execute command +[**SessionExecuteCommand**](WorkspaceToolboxAPI.md#SessionExecuteCommand) | **Post** /workspace/{workspaceId}/toolbox/process/session/{sessionId}/exec | Execute command in session ## CreateSession -> CreateSession(ctx, workspaceId, projectId).Params(params).Execute() +> CreateSession(ctx, workspaceId).Params(params).Execute() Create exec session @@ -63,12 +63,11 @@ import ( func main() { workspaceId := "workspaceId_example" // string | Workspace ID or Name - projectId := "projectId_example" // string | Project ID params := *openapiclient.NewCreateSessionRequest("SessionId_example") // CreateSessionRequest | Create session request configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - r, err := apiClient.WorkspaceToolboxAPI.CreateSession(context.Background(), workspaceId, projectId).Params(params).Execute() + r, err := apiClient.WorkspaceToolboxAPI.CreateSession(context.Background(), workspaceId).Params(params).Execute() if err != nil { fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceToolboxAPI.CreateSession``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) @@ -83,7 +82,6 @@ Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. **workspaceId** | **string** | Workspace ID or Name | -**projectId** | **string** | Project ID | ### Other Parameters @@ -93,7 +91,6 @@ Other parameters are passed through a pointer to a apiCreateSessionRequest struc Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - **params** | [**CreateSessionRequest**](CreateSessionRequest.md) | Create session request | ### Return type @@ -116,7 +113,7 @@ Name | Type | Description | Notes ## DeleteSession -> DeleteSession(ctx, workspaceId, projectId, sessionId).Execute() +> DeleteSession(ctx, workspaceId, sessionId).Execute() Delete session @@ -136,12 +133,11 @@ import ( func main() { workspaceId := "workspaceId_example" // string | Workspace ID or Name - projectId := "projectId_example" // string | Project ID sessionId := "sessionId_example" // string | Session ID configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - r, err := apiClient.WorkspaceToolboxAPI.DeleteSession(context.Background(), workspaceId, projectId, sessionId).Execute() + r, err := apiClient.WorkspaceToolboxAPI.DeleteSession(context.Background(), workspaceId, sessionId).Execute() if err != nil { fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceToolboxAPI.DeleteSession``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) @@ -156,7 +152,6 @@ Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. **workspaceId** | **string** | Workspace ID or Name | -**projectId** | **string** | Project ID | **sessionId** | **string** | Session ID | ### Other Parameters @@ -169,7 +164,6 @@ Name | Type | Description | Notes - ### Return type (empty response body) @@ -190,7 +184,7 @@ Name | Type | Description | Notes ## FsCreateFolder -> FsCreateFolder(ctx, workspaceId, projectId).Path(path).Mode(mode).Execute() +> FsCreateFolder(ctx, workspaceId).Path(path).Mode(mode).Execute() Create folder @@ -210,13 +204,12 @@ import ( func main() { workspaceId := "workspaceId_example" // string | Workspace ID or Name - projectId := "projectId_example" // string | Project ID path := "path_example" // string | Path mode := "mode_example" // string | Mode configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - r, err := apiClient.WorkspaceToolboxAPI.FsCreateFolder(context.Background(), workspaceId, projectId).Path(path).Mode(mode).Execute() + r, err := apiClient.WorkspaceToolboxAPI.FsCreateFolder(context.Background(), workspaceId).Path(path).Mode(mode).Execute() if err != nil { fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceToolboxAPI.FsCreateFolder``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) @@ -231,7 +224,6 @@ Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. **workspaceId** | **string** | Workspace ID or Name | -**projectId** | **string** | Project ID | ### Other Parameters @@ -241,7 +233,6 @@ Other parameters are passed through a pointer to a apiFsCreateFolderRequest stru Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - **path** | **string** | Path | **mode** | **string** | Mode | @@ -265,7 +256,7 @@ Name | Type | Description | Notes ## FsDeleteFile -> FsDeleteFile(ctx, workspaceId, projectId).Path(path).Execute() +> FsDeleteFile(ctx, workspaceId).Path(path).Execute() Delete file @@ -285,12 +276,11 @@ import ( func main() { workspaceId := "workspaceId_example" // string | Workspace ID or Name - projectId := "projectId_example" // string | Project ID path := "path_example" // string | Path configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - r, err := apiClient.WorkspaceToolboxAPI.FsDeleteFile(context.Background(), workspaceId, projectId).Path(path).Execute() + r, err := apiClient.WorkspaceToolboxAPI.FsDeleteFile(context.Background(), workspaceId).Path(path).Execute() if err != nil { fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceToolboxAPI.FsDeleteFile``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) @@ -305,7 +295,6 @@ Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. **workspaceId** | **string** | Workspace ID or Name | -**projectId** | **string** | Project ID | ### Other Parameters @@ -315,7 +304,6 @@ Other parameters are passed through a pointer to a apiFsDeleteFileRequest struct Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - **path** | **string** | Path | ### Return type @@ -338,7 +326,7 @@ Name | Type | Description | Notes ## FsDownloadFile -> *os.File FsDownloadFile(ctx, workspaceId, projectId).Path(path).Execute() +> *os.File FsDownloadFile(ctx, workspaceId).Path(path).Execute() Download file @@ -358,12 +346,11 @@ import ( func main() { workspaceId := "workspaceId_example" // string | Workspace ID or Name - projectId := "projectId_example" // string | Project ID path := "path_example" // string | Path configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.WorkspaceToolboxAPI.FsDownloadFile(context.Background(), workspaceId, projectId).Path(path).Execute() + resp, r, err := apiClient.WorkspaceToolboxAPI.FsDownloadFile(context.Background(), workspaceId).Path(path).Execute() if err != nil { fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceToolboxAPI.FsDownloadFile``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) @@ -380,7 +367,6 @@ Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. **workspaceId** | **string** | Workspace ID or Name | -**projectId** | **string** | Project ID | ### Other Parameters @@ -390,7 +376,6 @@ Other parameters are passed through a pointer to a apiFsDownloadFileRequest stru Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - **path** | **string** | Path | ### Return type @@ -413,7 +398,7 @@ Name | Type | Description | Notes ## FsFindInFiles -> []Match FsFindInFiles(ctx, workspaceId, projectId).Path(path).Pattern(pattern).Execute() +> []Match FsFindInFiles(ctx, workspaceId).Path(path).Pattern(pattern).Execute() Search for text/pattern in files @@ -433,13 +418,12 @@ import ( func main() { workspaceId := "workspaceId_example" // string | Workspace ID or Name - projectId := "projectId_example" // string | Project ID path := "path_example" // string | Path pattern := "pattern_example" // string | Pattern configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.WorkspaceToolboxAPI.FsFindInFiles(context.Background(), workspaceId, projectId).Path(path).Pattern(pattern).Execute() + resp, r, err := apiClient.WorkspaceToolboxAPI.FsFindInFiles(context.Background(), workspaceId).Path(path).Pattern(pattern).Execute() if err != nil { fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceToolboxAPI.FsFindInFiles``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) @@ -456,7 +440,6 @@ Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. **workspaceId** | **string** | Workspace ID or Name | -**projectId** | **string** | Project ID | ### Other Parameters @@ -466,7 +449,6 @@ Other parameters are passed through a pointer to a apiFsFindInFilesRequest struc Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - **path** | **string** | Path | **pattern** | **string** | Pattern | @@ -490,7 +472,7 @@ Name | Type | Description | Notes ## FsGetFileDetails -> FileInfo FsGetFileDetails(ctx, workspaceId, projectId).Path(path).Execute() +> FileInfo FsGetFileDetails(ctx, workspaceId).Path(path).Execute() Get file info @@ -510,12 +492,11 @@ import ( func main() { workspaceId := "workspaceId_example" // string | Workspace ID or Name - projectId := "projectId_example" // string | Project ID path := "path_example" // string | Path configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.WorkspaceToolboxAPI.FsGetFileDetails(context.Background(), workspaceId, projectId).Path(path).Execute() + resp, r, err := apiClient.WorkspaceToolboxAPI.FsGetFileDetails(context.Background(), workspaceId).Path(path).Execute() if err != nil { fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceToolboxAPI.FsGetFileDetails``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) @@ -532,7 +513,6 @@ Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. **workspaceId** | **string** | Workspace ID or Name | -**projectId** | **string** | Project ID | ### Other Parameters @@ -542,7 +522,6 @@ Other parameters are passed through a pointer to a apiFsGetFileDetailsRequest st Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - **path** | **string** | Path | ### Return type @@ -565,7 +544,7 @@ Name | Type | Description | Notes ## FsListFiles -> []FileInfo FsListFiles(ctx, workspaceId, projectId).Path(path).Execute() +> []FileInfo FsListFiles(ctx, workspaceId).Path(path).Execute() List files @@ -585,12 +564,11 @@ import ( func main() { workspaceId := "workspaceId_example" // string | Workspace ID or Name - projectId := "projectId_example" // string | Project ID path := "path_example" // string | Path (optional) configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.WorkspaceToolboxAPI.FsListFiles(context.Background(), workspaceId, projectId).Path(path).Execute() + resp, r, err := apiClient.WorkspaceToolboxAPI.FsListFiles(context.Background(), workspaceId).Path(path).Execute() if err != nil { fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceToolboxAPI.FsListFiles``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) @@ -607,7 +585,6 @@ Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. **workspaceId** | **string** | Workspace ID or Name | -**projectId** | **string** | Project ID | ### Other Parameters @@ -617,7 +594,6 @@ Other parameters are passed through a pointer to a apiFsListFilesRequest struct Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - **path** | **string** | Path | ### Return type @@ -640,7 +616,7 @@ Name | Type | Description | Notes ## FsMoveFile -> FsMoveFile(ctx, workspaceId, projectId).Source(source).Destination(destination).Execute() +> FsMoveFile(ctx, workspaceId).Source(source).Destination(destination).Execute() Create folder @@ -660,13 +636,12 @@ import ( func main() { workspaceId := "workspaceId_example" // string | Workspace ID or Name - projectId := "projectId_example" // string | Project ID source := "source_example" // string | Source path destination := "destination_example" // string | Destination path configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - r, err := apiClient.WorkspaceToolboxAPI.FsMoveFile(context.Background(), workspaceId, projectId).Source(source).Destination(destination).Execute() + r, err := apiClient.WorkspaceToolboxAPI.FsMoveFile(context.Background(), workspaceId).Source(source).Destination(destination).Execute() if err != nil { fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceToolboxAPI.FsMoveFile``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) @@ -681,7 +656,6 @@ Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. **workspaceId** | **string** | Workspace ID or Name | -**projectId** | **string** | Project ID | ### Other Parameters @@ -691,7 +665,6 @@ Other parameters are passed through a pointer to a apiFsMoveFileRequest struct v Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - **source** | **string** | Source path | **destination** | **string** | Destination path | @@ -715,7 +688,7 @@ Name | Type | Description | Notes ## FsReplaceInFiles -> []ReplaceResult FsReplaceInFiles(ctx, workspaceId, projectId).Replace(replace).Execute() +> []ReplaceResult FsReplaceInFiles(ctx, workspaceId).Replace(replace).Execute() Repleace text/pattern in files @@ -735,12 +708,11 @@ import ( func main() { workspaceId := "workspaceId_example" // string | Workspace ID or Name - projectId := "projectId_example" // string | Project ID replace := *openapiclient.NewReplaceRequest([]string{"Files_example"}, "NewValue_example", "Pattern_example") // ReplaceRequest | ReplaceParams configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.WorkspaceToolboxAPI.FsReplaceInFiles(context.Background(), workspaceId, projectId).Replace(replace).Execute() + resp, r, err := apiClient.WorkspaceToolboxAPI.FsReplaceInFiles(context.Background(), workspaceId).Replace(replace).Execute() if err != nil { fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceToolboxAPI.FsReplaceInFiles``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) @@ -757,7 +729,6 @@ Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. **workspaceId** | **string** | Workspace ID or Name | -**projectId** | **string** | Project ID | ### Other Parameters @@ -767,7 +738,6 @@ Other parameters are passed through a pointer to a apiFsReplaceInFilesRequest st Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - **replace** | [**ReplaceRequest**](ReplaceRequest.md) | ReplaceParams | ### Return type @@ -790,7 +760,7 @@ Name | Type | Description | Notes ## FsSearchFiles -> SearchFilesResponse FsSearchFiles(ctx, workspaceId, projectId).Path(path).Pattern(pattern).Execute() +> SearchFilesResponse FsSearchFiles(ctx, workspaceId).Path(path).Pattern(pattern).Execute() Search for files @@ -810,13 +780,12 @@ import ( func main() { workspaceId := "workspaceId_example" // string | Workspace ID or Name - projectId := "projectId_example" // string | Project ID path := "path_example" // string | Path pattern := "pattern_example" // string | Pattern configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.WorkspaceToolboxAPI.FsSearchFiles(context.Background(), workspaceId, projectId).Path(path).Pattern(pattern).Execute() + resp, r, err := apiClient.WorkspaceToolboxAPI.FsSearchFiles(context.Background(), workspaceId).Path(path).Pattern(pattern).Execute() if err != nil { fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceToolboxAPI.FsSearchFiles``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) @@ -833,7 +802,6 @@ Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. **workspaceId** | **string** | Workspace ID or Name | -**projectId** | **string** | Project ID | ### Other Parameters @@ -843,7 +811,6 @@ Other parameters are passed through a pointer to a apiFsSearchFilesRequest struc Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - **path** | **string** | Path | **pattern** | **string** | Pattern | @@ -867,7 +834,7 @@ Name | Type | Description | Notes ## FsSetFilePermissions -> FsSetFilePermissions(ctx, workspaceId, projectId).Path(path).Owner(owner).Group(group).Mode(mode).Execute() +> FsSetFilePermissions(ctx, workspaceId).Path(path).Owner(owner).Group(group).Mode(mode).Execute() Set file owner/group/permissions @@ -887,7 +854,6 @@ import ( func main() { workspaceId := "workspaceId_example" // string | Workspace ID or Name - projectId := "projectId_example" // string | Project ID path := "path_example" // string | Path owner := "owner_example" // string | Owner (optional) group := "group_example" // string | Group (optional) @@ -895,7 +861,7 @@ func main() { configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - r, err := apiClient.WorkspaceToolboxAPI.FsSetFilePermissions(context.Background(), workspaceId, projectId).Path(path).Owner(owner).Group(group).Mode(mode).Execute() + r, err := apiClient.WorkspaceToolboxAPI.FsSetFilePermissions(context.Background(), workspaceId).Path(path).Owner(owner).Group(group).Mode(mode).Execute() if err != nil { fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceToolboxAPI.FsSetFilePermissions``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) @@ -910,7 +876,6 @@ Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. **workspaceId** | **string** | Workspace ID or Name | -**projectId** | **string** | Project ID | ### Other Parameters @@ -920,7 +885,6 @@ Other parameters are passed through a pointer to a apiFsSetFilePermissionsReques Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - **path** | **string** | Path | **owner** | **string** | Owner | **group** | **string** | Group | @@ -946,7 +910,7 @@ Name | Type | Description | Notes ## FsUploadFile -> FsUploadFile(ctx, workspaceId, projectId).Path(path).File(file).Execute() +> FsUploadFile(ctx, workspaceId).Path(path).File(file).Execute() Upload file @@ -966,13 +930,12 @@ import ( func main() { workspaceId := "workspaceId_example" // string | Workspace ID or Name - projectId := "projectId_example" // string | Project ID path := "path_example" // string | Path file := os.NewFile(1234, "some_file") // *os.File | File configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - r, err := apiClient.WorkspaceToolboxAPI.FsUploadFile(context.Background(), workspaceId, projectId).Path(path).File(file).Execute() + r, err := apiClient.WorkspaceToolboxAPI.FsUploadFile(context.Background(), workspaceId).Path(path).File(file).Execute() if err != nil { fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceToolboxAPI.FsUploadFile``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) @@ -987,7 +950,6 @@ Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. **workspaceId** | **string** | Workspace ID or Name | -**projectId** | **string** | Project ID | ### Other Parameters @@ -997,7 +959,6 @@ Other parameters are passed through a pointer to a apiFsUploadFileRequest struct Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - **path** | **string** | Path | **file** | ***os.File** | File | @@ -1019,11 +980,11 @@ Name | Type | Description | Notes [[Back to README]](../README.md) -## GetProjectDir +## GetSessionCommandLogs -> ProjectDirResponse GetProjectDir(ctx, workspaceId, projectId).Execute() +> string GetSessionCommandLogs(ctx, workspaceId, sessionId, commandId).Execute() -Get project dir +Get session command logs @@ -1041,17 +1002,18 @@ import ( func main() { workspaceId := "workspaceId_example" // string | Workspace ID or Name - projectId := "projectId_example" // string | Project ID + sessionId := "sessionId_example" // string | Session ID + commandId := "commandId_example" // string | Command ID configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.WorkspaceToolboxAPI.GetProjectDir(context.Background(), workspaceId, projectId).Execute() + resp, r, err := apiClient.WorkspaceToolboxAPI.GetSessionCommandLogs(context.Background(), workspaceId, sessionId, commandId).Execute() if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceToolboxAPI.GetProjectDir``: %v\n", err) + fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceToolboxAPI.GetSessionCommandLogs``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) } - // response from `GetProjectDir`: ProjectDirResponse - fmt.Fprintf(os.Stdout, "Response from `WorkspaceToolboxAPI.GetProjectDir`: %v\n", resp) + // response from `GetSessionCommandLogs`: string + fmt.Fprintf(os.Stdout, "Response from `WorkspaceToolboxAPI.GetSessionCommandLogs`: %v\n", resp) } ``` @@ -1062,11 +1024,12 @@ Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. **workspaceId** | **string** | Workspace ID or Name | -**projectId** | **string** | Project ID | +**sessionId** | **string** | Session ID | +**commandId** | **string** | Command ID | ### Other Parameters -Other parameters are passed through a pointer to a apiGetProjectDirRequest struct via the builder pattern +Other parameters are passed through a pointer to a apiGetSessionCommandLogsRequest struct via the builder pattern Name | Type | Description | Notes @@ -1074,9 +1037,10 @@ Name | Type | Description | Notes + ### Return type -[**ProjectDirResponse**](ProjectDirResponse.md) +**string** ### Authorization @@ -1085,18 +1049,18 @@ Name | Type | Description | Notes ### HTTP request headers - **Content-Type**: Not defined -- **Accept**: application/json +- **Accept**: */* [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) -## GetSessionCommandLogs +## GetWorkspaceDir -> string GetSessionCommandLogs(ctx, workspaceId, projectId, sessionId, commandId).Execute() +> WorkspaceDirResponse GetWorkspaceDir(ctx, workspaceId).Execute() -Get session command logs +Get workspace dir @@ -1114,19 +1078,16 @@ import ( func main() { workspaceId := "workspaceId_example" // string | Workspace ID or Name - projectId := "projectId_example" // string | Project ID - sessionId := "sessionId_example" // string | Session ID - commandId := "commandId_example" // string | Command ID configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.WorkspaceToolboxAPI.GetSessionCommandLogs(context.Background(), workspaceId, projectId, sessionId, commandId).Execute() + resp, r, err := apiClient.WorkspaceToolboxAPI.GetWorkspaceDir(context.Background(), workspaceId).Execute() if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceToolboxAPI.GetSessionCommandLogs``: %v\n", err) + fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceToolboxAPI.GetWorkspaceDir``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) } - // response from `GetSessionCommandLogs`: string - fmt.Fprintf(os.Stdout, "Response from `WorkspaceToolboxAPI.GetSessionCommandLogs`: %v\n", resp) + // response from `GetWorkspaceDir`: WorkspaceDirResponse + fmt.Fprintf(os.Stdout, "Response from `WorkspaceToolboxAPI.GetWorkspaceDir`: %v\n", resp) } ``` @@ -1137,25 +1098,19 @@ Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. **workspaceId** | **string** | Workspace ID or Name | -**projectId** | **string** | Project ID | -**sessionId** | **string** | Session ID | -**commandId** | **string** | Command ID | ### Other Parameters -Other parameters are passed through a pointer to a apiGetSessionCommandLogsRequest struct via the builder pattern +Other parameters are passed through a pointer to a apiGetWorkspaceDirRequest struct via the builder pattern Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - - - ### Return type -**string** +[**WorkspaceDirResponse**](WorkspaceDirResponse.md) ### Authorization @@ -1164,7 +1119,7 @@ Name | Type | Description | Notes ### HTTP request headers - **Content-Type**: Not defined -- **Accept**: */* +- **Accept**: application/json [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) @@ -1173,7 +1128,7 @@ Name | Type | Description | Notes ## GitAddFiles -> GitAddFiles(ctx, workspaceId, projectId).Params(params).Execute() +> GitAddFiles(ctx, workspaceId).Params(params).Execute() Add files @@ -1193,12 +1148,11 @@ import ( func main() { workspaceId := "workspaceId_example" // string | Workspace ID or Name - projectId := "projectId_example" // string | Project ID params := *openapiclient.NewGitAddRequest([]string{"Files_example"}, "Path_example") // GitAddRequest | GitAddRequest configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - r, err := apiClient.WorkspaceToolboxAPI.GitAddFiles(context.Background(), workspaceId, projectId).Params(params).Execute() + r, err := apiClient.WorkspaceToolboxAPI.GitAddFiles(context.Background(), workspaceId).Params(params).Execute() if err != nil { fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceToolboxAPI.GitAddFiles``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) @@ -1213,7 +1167,6 @@ Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. **workspaceId** | **string** | Workspace ID or Name | -**projectId** | **string** | Project ID | ### Other Parameters @@ -1223,7 +1176,6 @@ Other parameters are passed through a pointer to a apiGitAddFilesRequest struct Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - **params** | [**GitAddRequest**](GitAddRequest.md) | GitAddRequest | ### Return type @@ -1246,7 +1198,7 @@ Name | Type | Description | Notes ## GitBranchList -> ListBranchResponse GitBranchList(ctx, workspaceId, projectId).Path(path).Execute() +> ListBranchResponse GitBranchList(ctx, workspaceId).Path(path).Execute() Get branch list @@ -1266,12 +1218,11 @@ import ( func main() { workspaceId := "workspaceId_example" // string | Workspace ID or Name - projectId := "projectId_example" // string | Project ID path := "path_example" // string | Path to git repository configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.WorkspaceToolboxAPI.GitBranchList(context.Background(), workspaceId, projectId).Path(path).Execute() + resp, r, err := apiClient.WorkspaceToolboxAPI.GitBranchList(context.Background(), workspaceId).Path(path).Execute() if err != nil { fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceToolboxAPI.GitBranchList``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) @@ -1288,7 +1239,6 @@ Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. **workspaceId** | **string** | Workspace ID or Name | -**projectId** | **string** | Project ID | ### Other Parameters @@ -1298,7 +1248,6 @@ Other parameters are passed through a pointer to a apiGitBranchListRequest struc Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - **path** | **string** | Path to git repository | ### Return type @@ -1321,7 +1270,7 @@ Name | Type | Description | Notes ## GitCloneRepository -> GitCloneRepository(ctx, workspaceId, projectId).Params(params).Execute() +> GitCloneRepository(ctx, workspaceId).Params(params).Execute() Clone git repository @@ -1341,12 +1290,11 @@ import ( func main() { workspaceId := "workspaceId_example" // string | Workspace ID or Name - projectId := "projectId_example" // string | Project ID params := *openapiclient.NewGitCloneRequest("Path_example", "Url_example") // GitCloneRequest | GitCloneRequest configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - r, err := apiClient.WorkspaceToolboxAPI.GitCloneRepository(context.Background(), workspaceId, projectId).Params(params).Execute() + r, err := apiClient.WorkspaceToolboxAPI.GitCloneRepository(context.Background(), workspaceId).Params(params).Execute() if err != nil { fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceToolboxAPI.GitCloneRepository``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) @@ -1361,7 +1309,6 @@ Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. **workspaceId** | **string** | Workspace ID or Name | -**projectId** | **string** | Project ID | ### Other Parameters @@ -1371,7 +1318,6 @@ Other parameters are passed through a pointer to a apiGitCloneRepositoryRequest Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - **params** | [**GitCloneRequest**](GitCloneRequest.md) | GitCloneRequest | ### Return type @@ -1394,7 +1340,7 @@ Name | Type | Description | Notes ## GitCommitChanges -> GitCommitResponse GitCommitChanges(ctx, workspaceId, projectId).Params(params).Execute() +> GitCommitResponse GitCommitChanges(ctx, workspaceId).Params(params).Execute() Commit changes @@ -1414,12 +1360,11 @@ import ( func main() { workspaceId := "workspaceId_example" // string | Workspace ID or Name - projectId := "projectId_example" // string | Project ID params := *openapiclient.NewGitCommitRequest("Author_example", "Email_example", "Message_example", "Path_example") // GitCommitRequest | GitCommitRequest configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.WorkspaceToolboxAPI.GitCommitChanges(context.Background(), workspaceId, projectId).Params(params).Execute() + resp, r, err := apiClient.WorkspaceToolboxAPI.GitCommitChanges(context.Background(), workspaceId).Params(params).Execute() if err != nil { fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceToolboxAPI.GitCommitChanges``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) @@ -1436,7 +1381,6 @@ Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. **workspaceId** | **string** | Workspace ID or Name | -**projectId** | **string** | Project ID | ### Other Parameters @@ -1446,7 +1390,6 @@ Other parameters are passed through a pointer to a apiGitCommitChangesRequest st Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - **params** | [**GitCommitRequest**](GitCommitRequest.md) | GitCommitRequest | ### Return type @@ -1469,7 +1412,7 @@ Name | Type | Description | Notes ## GitCommitHistory -> []GitCommitInfo GitCommitHistory(ctx, workspaceId, projectId).Path(path).Execute() +> []GitCommitInfo GitCommitHistory(ctx, workspaceId).Path(path).Execute() Get commit history @@ -1489,12 +1432,11 @@ import ( func main() { workspaceId := "workspaceId_example" // string | Workspace ID or Name - projectId := "projectId_example" // string | Project ID path := "path_example" // string | Path to git repository configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.WorkspaceToolboxAPI.GitCommitHistory(context.Background(), workspaceId, projectId).Path(path).Execute() + resp, r, err := apiClient.WorkspaceToolboxAPI.GitCommitHistory(context.Background(), workspaceId).Path(path).Execute() if err != nil { fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceToolboxAPI.GitCommitHistory``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) @@ -1511,7 +1453,6 @@ Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. **workspaceId** | **string** | Workspace ID or Name | -**projectId** | **string** | Project ID | ### Other Parameters @@ -1521,7 +1462,6 @@ Other parameters are passed through a pointer to a apiGitCommitHistoryRequest st Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - **path** | **string** | Path to git repository | ### Return type @@ -1544,7 +1484,7 @@ Name | Type | Description | Notes ## GitCreateBranch -> GitCreateBranch(ctx, workspaceId, projectId).Params(params).Execute() +> GitCreateBranch(ctx, workspaceId).Params(params).Execute() Create branch @@ -1564,12 +1504,11 @@ import ( func main() { workspaceId := "workspaceId_example" // string | Workspace ID or Name - projectId := "projectId_example" // string | Project ID params := *openapiclient.NewGitBranchRequest("Name_example", "Path_example") // GitBranchRequest | GitBranchRequest configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - r, err := apiClient.WorkspaceToolboxAPI.GitCreateBranch(context.Background(), workspaceId, projectId).Params(params).Execute() + r, err := apiClient.WorkspaceToolboxAPI.GitCreateBranch(context.Background(), workspaceId).Params(params).Execute() if err != nil { fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceToolboxAPI.GitCreateBranch``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) @@ -1584,7 +1523,6 @@ Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. **workspaceId** | **string** | Workspace ID or Name | -**projectId** | **string** | Project ID | ### Other Parameters @@ -1594,7 +1532,6 @@ Other parameters are passed through a pointer to a apiGitCreateBranchRequest str Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - **params** | [**GitBranchRequest**](GitBranchRequest.md) | GitBranchRequest | ### Return type @@ -1617,7 +1554,7 @@ Name | Type | Description | Notes ## GitGitStatus -> GitStatus GitGitStatus(ctx, workspaceId, projectId).Path(path).Execute() +> GitStatus GitGitStatus(ctx, workspaceId).Path(path).Execute() Get git status @@ -1637,12 +1574,11 @@ import ( func main() { workspaceId := "workspaceId_example" // string | Workspace ID or Name - projectId := "projectId_example" // string | Project ID path := "path_example" // string | Path to git repository configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.WorkspaceToolboxAPI.GitGitStatus(context.Background(), workspaceId, projectId).Path(path).Execute() + resp, r, err := apiClient.WorkspaceToolboxAPI.GitGitStatus(context.Background(), workspaceId).Path(path).Execute() if err != nil { fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceToolboxAPI.GitGitStatus``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) @@ -1659,7 +1595,6 @@ Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. **workspaceId** | **string** | Workspace ID or Name | -**projectId** | **string** | Project ID | ### Other Parameters @@ -1669,7 +1604,6 @@ Other parameters are passed through a pointer to a apiGitGitStatusRequest struct Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - **path** | **string** | Path to git repository | ### Return type @@ -1692,7 +1626,7 @@ Name | Type | Description | Notes ## GitPullChanges -> GitPullChanges(ctx, workspaceId, projectId).Params(params).Execute() +> GitPullChanges(ctx, workspaceId).Params(params).Execute() Pull changes @@ -1712,12 +1646,11 @@ import ( func main() { workspaceId := "workspaceId_example" // string | Workspace ID or Name - projectId := "projectId_example" // string | Project ID params := *openapiclient.NewGitRepoRequest("Path_example") // GitRepoRequest | Git pull request configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - r, err := apiClient.WorkspaceToolboxAPI.GitPullChanges(context.Background(), workspaceId, projectId).Params(params).Execute() + r, err := apiClient.WorkspaceToolboxAPI.GitPullChanges(context.Background(), workspaceId).Params(params).Execute() if err != nil { fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceToolboxAPI.GitPullChanges``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) @@ -1732,7 +1665,6 @@ Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. **workspaceId** | **string** | Workspace ID or Name | -**projectId** | **string** | Project ID | ### Other Parameters @@ -1742,7 +1674,6 @@ Other parameters are passed through a pointer to a apiGitPullChangesRequest stru Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - **params** | [**GitRepoRequest**](GitRepoRequest.md) | Git pull request | ### Return type @@ -1765,7 +1696,7 @@ Name | Type | Description | Notes ## GitPushChanges -> GitPushChanges(ctx, workspaceId, projectId).Params(params).Execute() +> GitPushChanges(ctx, workspaceId).Params(params).Execute() Push changes @@ -1785,12 +1716,11 @@ import ( func main() { workspaceId := "workspaceId_example" // string | Workspace ID or Name - projectId := "projectId_example" // string | Project ID params := *openapiclient.NewGitRepoRequest("Path_example") // GitRepoRequest | Git push request configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - r, err := apiClient.WorkspaceToolboxAPI.GitPushChanges(context.Background(), workspaceId, projectId).Params(params).Execute() + r, err := apiClient.WorkspaceToolboxAPI.GitPushChanges(context.Background(), workspaceId).Params(params).Execute() if err != nil { fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceToolboxAPI.GitPushChanges``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) @@ -1805,7 +1735,6 @@ Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. **workspaceId** | **string** | Workspace ID or Name | -**projectId** | **string** | Project ID | ### Other Parameters @@ -1815,7 +1744,6 @@ Other parameters are passed through a pointer to a apiGitPushChangesRequest stru Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - **params** | [**GitRepoRequest**](GitRepoRequest.md) | Git push request | ### Return type @@ -1838,7 +1766,7 @@ Name | Type | Description | Notes ## ListSessions -> []Session ListSessions(ctx, workspaceId, projectId).Execute() +> []Session ListSessions(ctx, workspaceId).Execute() List sessions @@ -1858,11 +1786,10 @@ import ( func main() { workspaceId := "workspaceId_example" // string | Workspace ID or Name - projectId := "projectId_example" // string | Project ID configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.WorkspaceToolboxAPI.ListSessions(context.Background(), workspaceId, projectId).Execute() + resp, r, err := apiClient.WorkspaceToolboxAPI.ListSessions(context.Background(), workspaceId).Execute() if err != nil { fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceToolboxAPI.ListSessions``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) @@ -1879,7 +1806,6 @@ Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. **workspaceId** | **string** | Workspace ID or Name | -**projectId** | **string** | Project ID | ### Other Parameters @@ -1890,7 +1816,6 @@ Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - ### Return type [**[]Session**](Session.md) @@ -1911,7 +1836,7 @@ Name | Type | Description | Notes ## LspCompletions -> CompletionList LspCompletions(ctx, workspaceId, projectId).Params(params).Execute() +> CompletionList LspCompletions(ctx, workspaceId).Params(params).Execute() Get Lsp Completions @@ -1931,12 +1856,11 @@ import ( func main() { workspaceId := "workspaceId_example" // string | Workspace ID or Name - projectId := "projectId_example" // string | Project ID params := *openapiclient.NewLspCompletionParams("LanguageId_example", "PathToProject_example", *openapiclient.NewPosition(int32(123), int32(123)), "Uri_example") // LspCompletionParams | LspCompletionParams configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.WorkspaceToolboxAPI.LspCompletions(context.Background(), workspaceId, projectId).Params(params).Execute() + resp, r, err := apiClient.WorkspaceToolboxAPI.LspCompletions(context.Background(), workspaceId).Params(params).Execute() if err != nil { fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceToolboxAPI.LspCompletions``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) @@ -1953,7 +1877,6 @@ Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. **workspaceId** | **string** | Workspace ID or Name | -**projectId** | **string** | Project ID | ### Other Parameters @@ -1963,7 +1886,6 @@ Other parameters are passed through a pointer to a apiLspCompletionsRequest stru Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - **params** | [**LspCompletionParams**](LspCompletionParams.md) | LspCompletionParams | ### Return type @@ -1986,7 +1908,7 @@ Name | Type | Description | Notes ## LspDidClose -> LspDidClose(ctx, workspaceId, projectId).Params(params).Execute() +> LspDidClose(ctx, workspaceId).Params(params).Execute() Call Lsp DidClose @@ -2006,12 +1928,11 @@ import ( func main() { workspaceId := "workspaceId_example" // string | Workspace ID or Name - projectId := "projectId_example" // string | Project ID params := *openapiclient.NewLspDocumentRequest("LanguageId_example", "PathToProject_example", "Uri_example") // LspDocumentRequest | LspDocumentRequest configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - r, err := apiClient.WorkspaceToolboxAPI.LspDidClose(context.Background(), workspaceId, projectId).Params(params).Execute() + r, err := apiClient.WorkspaceToolboxAPI.LspDidClose(context.Background(), workspaceId).Params(params).Execute() if err != nil { fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceToolboxAPI.LspDidClose``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) @@ -2026,7 +1947,6 @@ Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. **workspaceId** | **string** | Workspace ID or Name | -**projectId** | **string** | Project ID | ### Other Parameters @@ -2036,7 +1956,6 @@ Other parameters are passed through a pointer to a apiLspDidCloseRequest struct Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - **params** | [**LspDocumentRequest**](LspDocumentRequest.md) | LspDocumentRequest | ### Return type @@ -2059,7 +1978,7 @@ Name | Type | Description | Notes ## LspDidOpen -> LspDidOpen(ctx, workspaceId, projectId).Params(params).Execute() +> LspDidOpen(ctx, workspaceId).Params(params).Execute() Call Lsp DidOpen @@ -2079,12 +1998,11 @@ import ( func main() { workspaceId := "workspaceId_example" // string | Workspace ID or Name - projectId := "projectId_example" // string | Project ID params := *openapiclient.NewLspDocumentRequest("LanguageId_example", "PathToProject_example", "Uri_example") // LspDocumentRequest | LspDocumentRequest configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - r, err := apiClient.WorkspaceToolboxAPI.LspDidOpen(context.Background(), workspaceId, projectId).Params(params).Execute() + r, err := apiClient.WorkspaceToolboxAPI.LspDidOpen(context.Background(), workspaceId).Params(params).Execute() if err != nil { fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceToolboxAPI.LspDidOpen``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) @@ -2099,7 +2017,6 @@ Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. **workspaceId** | **string** | Workspace ID or Name | -**projectId** | **string** | Project ID | ### Other Parameters @@ -2109,7 +2026,6 @@ Other parameters are passed through a pointer to a apiLspDidOpenRequest struct v Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - **params** | [**LspDocumentRequest**](LspDocumentRequest.md) | LspDocumentRequest | ### Return type @@ -2132,7 +2048,7 @@ Name | Type | Description | Notes ## LspDocumentSymbols -> []LspSymbol LspDocumentSymbols(ctx, workspaceId, projectId).LanguageId(languageId).PathToProject(pathToProject).Uri(uri).Execute() +> []LspSymbol LspDocumentSymbols(ctx, workspaceId).LanguageId(languageId).PathToProject(pathToProject).Uri(uri).Execute() Call Lsp DocumentSymbols @@ -2152,14 +2068,13 @@ import ( func main() { workspaceId := "workspaceId_example" // string | Workspace ID or Name - projectId := "projectId_example" // string | Project ID languageId := "languageId_example" // string | Language ID pathToProject := "pathToProject_example" // string | Path to project uri := "uri_example" // string | Document Uri configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.WorkspaceToolboxAPI.LspDocumentSymbols(context.Background(), workspaceId, projectId).LanguageId(languageId).PathToProject(pathToProject).Uri(uri).Execute() + resp, r, err := apiClient.WorkspaceToolboxAPI.LspDocumentSymbols(context.Background(), workspaceId).LanguageId(languageId).PathToProject(pathToProject).Uri(uri).Execute() if err != nil { fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceToolboxAPI.LspDocumentSymbols``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) @@ -2176,7 +2091,6 @@ Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. **workspaceId** | **string** | Workspace ID or Name | -**projectId** | **string** | Project ID | ### Other Parameters @@ -2186,7 +2100,6 @@ Other parameters are passed through a pointer to a apiLspDocumentSymbolsRequest Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - **languageId** | **string** | Language ID | **pathToProject** | **string** | Path to project | **uri** | **string** | Document Uri | @@ -2211,7 +2124,7 @@ Name | Type | Description | Notes ## LspStart -> LspStart(ctx, workspaceId, projectId).Params(params).Execute() +> LspStart(ctx, workspaceId).Params(params).Execute() Start Lsp server @@ -2231,12 +2144,11 @@ import ( func main() { workspaceId := "workspaceId_example" // string | Workspace ID or Name - projectId := "projectId_example" // string | Project ID params := *openapiclient.NewLspServerRequest("LanguageId_example", "PathToProject_example") // LspServerRequest | LspServerRequest configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - r, err := apiClient.WorkspaceToolboxAPI.LspStart(context.Background(), workspaceId, projectId).Params(params).Execute() + r, err := apiClient.WorkspaceToolboxAPI.LspStart(context.Background(), workspaceId).Params(params).Execute() if err != nil { fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceToolboxAPI.LspStart``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) @@ -2251,7 +2163,6 @@ Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. **workspaceId** | **string** | Workspace ID or Name | -**projectId** | **string** | Project ID | ### Other Parameters @@ -2261,7 +2172,6 @@ Other parameters are passed through a pointer to a apiLspStartRequest struct via Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - **params** | [**LspServerRequest**](LspServerRequest.md) | LspServerRequest | ### Return type @@ -2284,7 +2194,7 @@ Name | Type | Description | Notes ## LspStop -> LspStop(ctx, workspaceId, projectId).Params(params).Execute() +> LspStop(ctx, workspaceId).Params(params).Execute() Stop Lsp server @@ -2304,12 +2214,11 @@ import ( func main() { workspaceId := "workspaceId_example" // string | Workspace ID or Name - projectId := "projectId_example" // string | Project ID params := *openapiclient.NewLspServerRequest("LanguageId_example", "PathToProject_example") // LspServerRequest | LspServerRequest configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - r, err := apiClient.WorkspaceToolboxAPI.LspStop(context.Background(), workspaceId, projectId).Params(params).Execute() + r, err := apiClient.WorkspaceToolboxAPI.LspStop(context.Background(), workspaceId).Params(params).Execute() if err != nil { fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceToolboxAPI.LspStop``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) @@ -2324,7 +2233,6 @@ Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. **workspaceId** | **string** | Workspace ID or Name | -**projectId** | **string** | Project ID | ### Other Parameters @@ -2334,7 +2242,6 @@ Other parameters are passed through a pointer to a apiLspStopRequest struct via Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - **params** | [**LspServerRequest**](LspServerRequest.md) | LspServerRequest | ### Return type @@ -2357,7 +2264,7 @@ Name | Type | Description | Notes ## LspWorkspaceSymbols -> []LspSymbol LspWorkspaceSymbols(ctx, workspaceId, projectId).LanguageId(languageId).PathToProject(pathToProject).Query(query).Execute() +> []LspSymbol LspWorkspaceSymbols(ctx, workspaceId).LanguageId(languageId).PathToProject(pathToProject).Query(query).Execute() Call Lsp WorkspaceSymbols @@ -2377,14 +2284,13 @@ import ( func main() { workspaceId := "workspaceId_example" // string | Workspace ID or Name - projectId := "projectId_example" // string | Project ID languageId := "languageId_example" // string | Language ID pathToProject := "pathToProject_example" // string | Path to project query := "query_example" // string | Symbol Query configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.WorkspaceToolboxAPI.LspWorkspaceSymbols(context.Background(), workspaceId, projectId).LanguageId(languageId).PathToProject(pathToProject).Query(query).Execute() + resp, r, err := apiClient.WorkspaceToolboxAPI.LspWorkspaceSymbols(context.Background(), workspaceId).LanguageId(languageId).PathToProject(pathToProject).Query(query).Execute() if err != nil { fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceToolboxAPI.LspWorkspaceSymbols``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) @@ -2401,7 +2307,6 @@ Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. **workspaceId** | **string** | Workspace ID or Name | -**projectId** | **string** | Project ID | ### Other Parameters @@ -2411,7 +2316,6 @@ Other parameters are passed through a pointer to a apiLspWorkspaceSymbolsRequest Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - **languageId** | **string** | Language ID | **pathToProject** | **string** | Path to project | **query** | **string** | Symbol Query | @@ -2436,7 +2340,7 @@ Name | Type | Description | Notes ## ProcessExecuteCommand -> ExecuteResponse ProcessExecuteCommand(ctx, workspaceId, projectId).Params(params).Execute() +> ExecuteResponse ProcessExecuteCommand(ctx, workspaceId).Params(params).Execute() Execute command @@ -2456,12 +2360,11 @@ import ( func main() { workspaceId := "workspaceId_example" // string | Workspace ID or Name - projectId := "projectId_example" // string | Project ID params := *openapiclient.NewExecuteRequest("Command_example") // ExecuteRequest | Execute command request configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.WorkspaceToolboxAPI.ProcessExecuteCommand(context.Background(), workspaceId, projectId).Params(params).Execute() + resp, r, err := apiClient.WorkspaceToolboxAPI.ProcessExecuteCommand(context.Background(), workspaceId).Params(params).Execute() if err != nil { fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceToolboxAPI.ProcessExecuteCommand``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) @@ -2478,7 +2381,6 @@ Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. **workspaceId** | **string** | Workspace ID or Name | -**projectId** | **string** | Project ID | ### Other Parameters @@ -2488,7 +2390,6 @@ Other parameters are passed through a pointer to a apiProcessExecuteCommandReque Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - **params** | [**ExecuteRequest**](ExecuteRequest.md) | Execute command request | ### Return type @@ -2511,7 +2412,7 @@ Name | Type | Description | Notes ## SessionExecuteCommand -> SessionExecuteResponse SessionExecuteCommand(ctx, workspaceId, projectId, sessionId).Params(params).Execute() +> SessionExecuteResponse SessionExecuteCommand(ctx, workspaceId, sessionId).Params(params).Execute() Execute command in session @@ -2531,13 +2432,12 @@ import ( func main() { workspaceId := "workspaceId_example" // string | Workspace ID or Name - projectId := "projectId_example" // string | Project ID sessionId := "sessionId_example" // string | Session ID params := *openapiclient.NewSessionExecuteRequest("Command_example") // SessionExecuteRequest | Execute command request configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.WorkspaceToolboxAPI.SessionExecuteCommand(context.Background(), workspaceId, projectId, sessionId).Params(params).Execute() + resp, r, err := apiClient.WorkspaceToolboxAPI.SessionExecuteCommand(context.Background(), workspaceId, sessionId).Params(params).Execute() if err != nil { fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceToolboxAPI.SessionExecuteCommand``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) @@ -2554,7 +2454,6 @@ Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. **workspaceId** | **string** | Workspace ID or Name | -**projectId** | **string** | Project ID | **sessionId** | **string** | Session ID | ### Other Parameters @@ -2566,7 +2465,6 @@ Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - **params** | [**SessionExecuteRequest**](SessionExecuteRequest.md) | Execute command request | ### Return type diff --git a/pkg/apiclient/model_api_key.go b/pkg/apiclient/model_api_key_view_dto.go similarity index 53% rename from pkg/apiclient/model_api_key.go rename to pkg/apiclient/model_api_key_view_dto.go index 4a891d3af3..3838c77456 100644 --- a/pkg/apiclient/model_api_key.go +++ b/pkg/apiclient/model_api_key_view_dto.go @@ -16,65 +16,64 @@ import ( "fmt" ) -// checks if the ApiKey type satisfies the MappedNullable interface at compile time -var _ MappedNullable = &ApiKey{} +// checks if the ApiKeyViewDTO type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &ApiKeyViewDTO{} -// ApiKey struct for ApiKey -type ApiKey struct { - KeyHash string `json:"keyHash"` - // Project or client name - Name string `json:"name"` - Type ApikeyApiKeyType `json:"type"` +// ApiKeyViewDTO struct for ApiKeyViewDTO +type ApiKeyViewDTO struct { + Current bool `json:"current"` + Name string `json:"name"` + Type ModelsApiKeyType `json:"type"` } -type _ApiKey ApiKey +type _ApiKeyViewDTO ApiKeyViewDTO -// NewApiKey instantiates a new ApiKey object +// NewApiKeyViewDTO instantiates a new ApiKeyViewDTO object // This constructor will assign default values to properties that have it defined, // and makes sure properties required by API are set, but the set of arguments // will change when the set of required properties is changed -func NewApiKey(keyHash string, name string, type_ ApikeyApiKeyType) *ApiKey { - this := ApiKey{} - this.KeyHash = keyHash +func NewApiKeyViewDTO(current bool, name string, type_ ModelsApiKeyType) *ApiKeyViewDTO { + this := ApiKeyViewDTO{} + this.Current = current this.Name = name this.Type = type_ return &this } -// NewApiKeyWithDefaults instantiates a new ApiKey object +// NewApiKeyViewDTOWithDefaults instantiates a new ApiKeyViewDTO object // This constructor will only assign default values to properties that have it defined, // but it doesn't guarantee that properties required by API are set -func NewApiKeyWithDefaults() *ApiKey { - this := ApiKey{} +func NewApiKeyViewDTOWithDefaults() *ApiKeyViewDTO { + this := ApiKeyViewDTO{} return &this } -// GetKeyHash returns the KeyHash field value -func (o *ApiKey) GetKeyHash() string { +// GetCurrent returns the Current field value +func (o *ApiKeyViewDTO) GetCurrent() bool { if o == nil { - var ret string + var ret bool return ret } - return o.KeyHash + return o.Current } -// GetKeyHashOk returns a tuple with the KeyHash field value +// GetCurrentOk returns a tuple with the Current field value // and a boolean to check if the value has been set. -func (o *ApiKey) GetKeyHashOk() (*string, bool) { +func (o *ApiKeyViewDTO) GetCurrentOk() (*bool, bool) { if o == nil { return nil, false } - return &o.KeyHash, true + return &o.Current, true } -// SetKeyHash sets field value -func (o *ApiKey) SetKeyHash(v string) { - o.KeyHash = v +// SetCurrent sets field value +func (o *ApiKeyViewDTO) SetCurrent(v bool) { + o.Current = v } // GetName returns the Name field value -func (o *ApiKey) GetName() string { +func (o *ApiKeyViewDTO) GetName() string { if o == nil { var ret string return ret @@ -85,7 +84,7 @@ func (o *ApiKey) GetName() string { // GetNameOk returns a tuple with the Name field value // and a boolean to check if the value has been set. -func (o *ApiKey) GetNameOk() (*string, bool) { +func (o *ApiKeyViewDTO) GetNameOk() (*string, bool) { if o == nil { return nil, false } @@ -93,14 +92,14 @@ func (o *ApiKey) GetNameOk() (*string, bool) { } // SetName sets field value -func (o *ApiKey) SetName(v string) { +func (o *ApiKeyViewDTO) SetName(v string) { o.Name = v } // GetType returns the Type field value -func (o *ApiKey) GetType() ApikeyApiKeyType { +func (o *ApiKeyViewDTO) GetType() ModelsApiKeyType { if o == nil { - var ret ApikeyApiKeyType + var ret ModelsApiKeyType return ret } @@ -109,7 +108,7 @@ func (o *ApiKey) GetType() ApikeyApiKeyType { // GetTypeOk returns a tuple with the Type field value // and a boolean to check if the value has been set. -func (o *ApiKey) GetTypeOk() (*ApikeyApiKeyType, bool) { +func (o *ApiKeyViewDTO) GetTypeOk() (*ModelsApiKeyType, bool) { if o == nil { return nil, false } @@ -117,11 +116,11 @@ func (o *ApiKey) GetTypeOk() (*ApikeyApiKeyType, bool) { } // SetType sets field value -func (o *ApiKey) SetType(v ApikeyApiKeyType) { +func (o *ApiKeyViewDTO) SetType(v ModelsApiKeyType) { o.Type = v } -func (o ApiKey) MarshalJSON() ([]byte, error) { +func (o ApiKeyViewDTO) MarshalJSON() ([]byte, error) { toSerialize, err := o.ToMap() if err != nil { return []byte{}, err @@ -129,20 +128,20 @@ func (o ApiKey) MarshalJSON() ([]byte, error) { return json.Marshal(toSerialize) } -func (o ApiKey) ToMap() (map[string]interface{}, error) { +func (o ApiKeyViewDTO) ToMap() (map[string]interface{}, error) { toSerialize := map[string]interface{}{} - toSerialize["keyHash"] = o.KeyHash + toSerialize["current"] = o.Current toSerialize["name"] = o.Name toSerialize["type"] = o.Type return toSerialize, nil } -func (o *ApiKey) UnmarshalJSON(data []byte) (err error) { +func (o *ApiKeyViewDTO) UnmarshalJSON(data []byte) (err error) { // This validates that all required properties are included in the JSON object // by unmarshalling the object into a generic map with string keys and checking // that every required field exists as a key in the generic map. requiredProperties := []string{ - "keyHash", + "current", "name", "type", } @@ -161,53 +160,53 @@ func (o *ApiKey) UnmarshalJSON(data []byte) (err error) { } } - varApiKey := _ApiKey{} + varApiKeyViewDTO := _ApiKeyViewDTO{} decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() - err = decoder.Decode(&varApiKey) + err = decoder.Decode(&varApiKeyViewDTO) if err != nil { return err } - *o = ApiKey(varApiKey) + *o = ApiKeyViewDTO(varApiKeyViewDTO) return err } -type NullableApiKey struct { - value *ApiKey +type NullableApiKeyViewDTO struct { + value *ApiKeyViewDTO isSet bool } -func (v NullableApiKey) Get() *ApiKey { +func (v NullableApiKeyViewDTO) Get() *ApiKeyViewDTO { return v.value } -func (v *NullableApiKey) Set(val *ApiKey) { +func (v *NullableApiKeyViewDTO) Set(val *ApiKeyViewDTO) { v.value = val v.isSet = true } -func (v NullableApiKey) IsSet() bool { +func (v NullableApiKeyViewDTO) IsSet() bool { return v.isSet } -func (v *NullableApiKey) Unset() { +func (v *NullableApiKeyViewDTO) Unset() { v.value = nil v.isSet = false } -func NewNullableApiKey(val *ApiKey) *NullableApiKey { - return &NullableApiKey{value: val, isSet: true} +func NewNullableApiKeyViewDTO(val *ApiKeyViewDTO) *NullableApiKeyViewDTO { + return &NullableApiKeyViewDTO{value: val, isSet: true} } -func (v NullableApiKey) MarshalJSON() ([]byte, error) { +func (v NullableApiKeyViewDTO) MarshalJSON() ([]byte, error) { return json.Marshal(v.value) } -func (v *NullableApiKey) UnmarshalJSON(src []byte) error { +func (v *NullableApiKeyViewDTO) UnmarshalJSON(src []byte) error { v.isSet = true return json.Unmarshal(src, &v.value) } diff --git a/pkg/apiclient/model_apikey_api_key_type.go b/pkg/apiclient/model_apikey_api_key_type.go deleted file mode 100644 index d75dfb81ff..0000000000 --- a/pkg/apiclient/model_apikey_api_key_type.go +++ /dev/null @@ -1,112 +0,0 @@ -/* -Daytona Server API - -Daytona Server API - -API version: v0.0.0-dev -*/ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package apiclient - -import ( - "encoding/json" - "fmt" -) - -// ApikeyApiKeyType the model 'ApikeyApiKeyType' -type ApikeyApiKeyType string - -// List of apikey.ApiKeyType -const ( - ApiKeyTypeClient ApikeyApiKeyType = "client" - ApiKeyTypeProject ApikeyApiKeyType = "project" - ApiKeyTypeWorkspace ApikeyApiKeyType = "workspace" -) - -// All allowed values of ApikeyApiKeyType enum -var AllowedApikeyApiKeyTypeEnumValues = []ApikeyApiKeyType{ - "client", - "project", - "workspace", -} - -func (v *ApikeyApiKeyType) UnmarshalJSON(src []byte) error { - var value string - err := json.Unmarshal(src, &value) - if err != nil { - return err - } - enumTypeValue := ApikeyApiKeyType(value) - for _, existing := range AllowedApikeyApiKeyTypeEnumValues { - if existing == enumTypeValue { - *v = enumTypeValue - return nil - } - } - - return fmt.Errorf("%+v is not a valid ApikeyApiKeyType", value) -} - -// NewApikeyApiKeyTypeFromValue returns a pointer to a valid ApikeyApiKeyType -// for the value passed as argument, or an error if the value passed is not allowed by the enum -func NewApikeyApiKeyTypeFromValue(v string) (*ApikeyApiKeyType, error) { - ev := ApikeyApiKeyType(v) - if ev.IsValid() { - return &ev, nil - } else { - return nil, fmt.Errorf("invalid value '%v' for ApikeyApiKeyType: valid values are %v", v, AllowedApikeyApiKeyTypeEnumValues) - } -} - -// IsValid return true if the value is valid for the enum, false otherwise -func (v ApikeyApiKeyType) IsValid() bool { - for _, existing := range AllowedApikeyApiKeyTypeEnumValues { - if existing == v { - return true - } - } - return false -} - -// Ptr returns reference to apikey.ApiKeyType value -func (v ApikeyApiKeyType) Ptr() *ApikeyApiKeyType { - return &v -} - -type NullableApikeyApiKeyType struct { - value *ApikeyApiKeyType - isSet bool -} - -func (v NullableApikeyApiKeyType) Get() *ApikeyApiKeyType { - return v.value -} - -func (v *NullableApikeyApiKeyType) Set(val *ApikeyApiKeyType) { - v.value = val - v.isSet = true -} - -func (v NullableApikeyApiKeyType) IsSet() bool { - return v.isSet -} - -func (v *NullableApikeyApiKeyType) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableApikeyApiKeyType(val *ApikeyApiKeyType) *NullableApikeyApiKeyType { - return &NullableApikeyApiKeyType{value: val, isSet: true} -} - -func (v NullableApikeyApiKeyType) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableApikeyApiKeyType) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/pkg/apiclient/model_build_build_state.go b/pkg/apiclient/model_build_build_state.go deleted file mode 100644 index c31c266c19..0000000000 --- a/pkg/apiclient/model_build_build_state.go +++ /dev/null @@ -1,122 +0,0 @@ -/* -Daytona Server API - -Daytona Server API - -API version: v0.0.0-dev -*/ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package apiclient - -import ( - "encoding/json" - "fmt" -) - -// BuildBuildState the model 'BuildBuildState' -type BuildBuildState string - -// List of build.BuildState -const ( - BuildStatePendingRun BuildBuildState = "pending-run" - BuildStateRunning BuildBuildState = "running" - BuildStateError BuildBuildState = "error" - BuildStateSuccess BuildBuildState = "success" - BuildStatePublished BuildBuildState = "published" - BuildStatePendingDelete BuildBuildState = "pending-delete" - BuildStatePendingForcedDelete BuildBuildState = "pending-forced-delete" - BuildStateDeleting BuildBuildState = "deleting" -) - -// All allowed values of BuildBuildState enum -var AllowedBuildBuildStateEnumValues = []BuildBuildState{ - "pending-run", - "running", - "error", - "success", - "published", - "pending-delete", - "pending-forced-delete", - "deleting", -} - -func (v *BuildBuildState) UnmarshalJSON(src []byte) error { - var value string - err := json.Unmarshal(src, &value) - if err != nil { - return err - } - enumTypeValue := BuildBuildState(value) - for _, existing := range AllowedBuildBuildStateEnumValues { - if existing == enumTypeValue { - *v = enumTypeValue - return nil - } - } - - return fmt.Errorf("%+v is not a valid BuildBuildState", value) -} - -// NewBuildBuildStateFromValue returns a pointer to a valid BuildBuildState -// for the value passed as argument, or an error if the value passed is not allowed by the enum -func NewBuildBuildStateFromValue(v string) (*BuildBuildState, error) { - ev := BuildBuildState(v) - if ev.IsValid() { - return &ev, nil - } else { - return nil, fmt.Errorf("invalid value '%v' for BuildBuildState: valid values are %v", v, AllowedBuildBuildStateEnumValues) - } -} - -// IsValid return true if the value is valid for the enum, false otherwise -func (v BuildBuildState) IsValid() bool { - for _, existing := range AllowedBuildBuildStateEnumValues { - if existing == v { - return true - } - } - return false -} - -// Ptr returns reference to build.BuildState value -func (v BuildBuildState) Ptr() *BuildBuildState { - return &v -} - -type NullableBuildBuildState struct { - value *BuildBuildState - isSet bool -} - -func (v NullableBuildBuildState) Get() *BuildBuildState { - return v.value -} - -func (v *NullableBuildBuildState) Set(val *BuildBuildState) { - v.value = val - v.isSet = true -} - -func (v NullableBuildBuildState) IsSet() bool { - return v.isSet -} - -func (v *NullableBuildBuildState) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableBuildBuildState(val *BuildBuildState) *NullableBuildBuildState { - return &NullableBuildBuildState{value: val, isSet: true} -} - -func (v NullableBuildBuildState) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableBuildBuildState) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/pkg/apiclient/model_build.go b/pkg/apiclient/model_build_dto.go similarity index 57% rename from pkg/apiclient/model_build.go rename to pkg/apiclient/model_build_dto.go index 5651cbcb24..0000a04940 100644 --- a/pkg/apiclient/model_build.go +++ b/pkg/apiclient/model_build_dto.go @@ -16,53 +16,54 @@ import ( "fmt" ) -// checks if the Build type satisfies the MappedNullable interface at compile time -var _ MappedNullable = &Build{} +// checks if the BuildDTO type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &BuildDTO{} -// Build struct for Build -type Build struct { +// BuildDTO struct for BuildDTO +type BuildDTO struct { BuildConfig *BuildConfig `json:"buildConfig,omitempty"` ContainerConfig ContainerConfig `json:"containerConfig"` CreatedAt string `json:"createdAt"` EnvVars map[string]string `json:"envVars"` Id string `json:"id"` Image *string `json:"image,omitempty"` - PrebuildId string `json:"prebuildId"` + LastJob *Job `json:"lastJob,omitempty"` + LastJobId *string `json:"lastJobId,omitempty"` + PrebuildId *string `json:"prebuildId,omitempty"` Repository GitRepository `json:"repository"` - State BuildBuildState `json:"state"` + State ResourceState `json:"state"` UpdatedAt string `json:"updatedAt"` User *string `json:"user,omitempty"` } -type _Build Build +type _BuildDTO BuildDTO -// NewBuild instantiates a new Build object +// NewBuildDTO instantiates a new BuildDTO object // This constructor will assign default values to properties that have it defined, // and makes sure properties required by API are set, but the set of arguments // will change when the set of required properties is changed -func NewBuild(containerConfig ContainerConfig, createdAt string, envVars map[string]string, id string, prebuildId string, repository GitRepository, state BuildBuildState, updatedAt string) *Build { - this := Build{} +func NewBuildDTO(containerConfig ContainerConfig, createdAt string, envVars map[string]string, id string, repository GitRepository, state ResourceState, updatedAt string) *BuildDTO { + this := BuildDTO{} this.ContainerConfig = containerConfig this.CreatedAt = createdAt this.EnvVars = envVars this.Id = id - this.PrebuildId = prebuildId this.Repository = repository this.State = state this.UpdatedAt = updatedAt return &this } -// NewBuildWithDefaults instantiates a new Build object +// NewBuildDTOWithDefaults instantiates a new BuildDTO object // This constructor will only assign default values to properties that have it defined, // but it doesn't guarantee that properties required by API are set -func NewBuildWithDefaults() *Build { - this := Build{} +func NewBuildDTOWithDefaults() *BuildDTO { + this := BuildDTO{} return &this } // GetBuildConfig returns the BuildConfig field value if set, zero value otherwise. -func (o *Build) GetBuildConfig() BuildConfig { +func (o *BuildDTO) GetBuildConfig() BuildConfig { if o == nil || IsNil(o.BuildConfig) { var ret BuildConfig return ret @@ -72,7 +73,7 @@ func (o *Build) GetBuildConfig() BuildConfig { // GetBuildConfigOk returns a tuple with the BuildConfig field value if set, nil otherwise // and a boolean to check if the value has been set. -func (o *Build) GetBuildConfigOk() (*BuildConfig, bool) { +func (o *BuildDTO) GetBuildConfigOk() (*BuildConfig, bool) { if o == nil || IsNil(o.BuildConfig) { return nil, false } @@ -80,7 +81,7 @@ func (o *Build) GetBuildConfigOk() (*BuildConfig, bool) { } // HasBuildConfig returns a boolean if a field has been set. -func (o *Build) HasBuildConfig() bool { +func (o *BuildDTO) HasBuildConfig() bool { if o != nil && !IsNil(o.BuildConfig) { return true } @@ -89,12 +90,12 @@ func (o *Build) HasBuildConfig() bool { } // SetBuildConfig gets a reference to the given BuildConfig and assigns it to the BuildConfig field. -func (o *Build) SetBuildConfig(v BuildConfig) { +func (o *BuildDTO) SetBuildConfig(v BuildConfig) { o.BuildConfig = &v } // GetContainerConfig returns the ContainerConfig field value -func (o *Build) GetContainerConfig() ContainerConfig { +func (o *BuildDTO) GetContainerConfig() ContainerConfig { if o == nil { var ret ContainerConfig return ret @@ -105,7 +106,7 @@ func (o *Build) GetContainerConfig() ContainerConfig { // GetContainerConfigOk returns a tuple with the ContainerConfig field value // and a boolean to check if the value has been set. -func (o *Build) GetContainerConfigOk() (*ContainerConfig, bool) { +func (o *BuildDTO) GetContainerConfigOk() (*ContainerConfig, bool) { if o == nil { return nil, false } @@ -113,12 +114,12 @@ func (o *Build) GetContainerConfigOk() (*ContainerConfig, bool) { } // SetContainerConfig sets field value -func (o *Build) SetContainerConfig(v ContainerConfig) { +func (o *BuildDTO) SetContainerConfig(v ContainerConfig) { o.ContainerConfig = v } // GetCreatedAt returns the CreatedAt field value -func (o *Build) GetCreatedAt() string { +func (o *BuildDTO) GetCreatedAt() string { if o == nil { var ret string return ret @@ -129,7 +130,7 @@ func (o *Build) GetCreatedAt() string { // GetCreatedAtOk returns a tuple with the CreatedAt field value // and a boolean to check if the value has been set. -func (o *Build) GetCreatedAtOk() (*string, bool) { +func (o *BuildDTO) GetCreatedAtOk() (*string, bool) { if o == nil { return nil, false } @@ -137,12 +138,12 @@ func (o *Build) GetCreatedAtOk() (*string, bool) { } // SetCreatedAt sets field value -func (o *Build) SetCreatedAt(v string) { +func (o *BuildDTO) SetCreatedAt(v string) { o.CreatedAt = v } // GetEnvVars returns the EnvVars field value -func (o *Build) GetEnvVars() map[string]string { +func (o *BuildDTO) GetEnvVars() map[string]string { if o == nil { var ret map[string]string return ret @@ -153,7 +154,7 @@ func (o *Build) GetEnvVars() map[string]string { // GetEnvVarsOk returns a tuple with the EnvVars field value // and a boolean to check if the value has been set. -func (o *Build) GetEnvVarsOk() (*map[string]string, bool) { +func (o *BuildDTO) GetEnvVarsOk() (*map[string]string, bool) { if o == nil { return nil, false } @@ -161,12 +162,12 @@ func (o *Build) GetEnvVarsOk() (*map[string]string, bool) { } // SetEnvVars sets field value -func (o *Build) SetEnvVars(v map[string]string) { +func (o *BuildDTO) SetEnvVars(v map[string]string) { o.EnvVars = v } // GetId returns the Id field value -func (o *Build) GetId() string { +func (o *BuildDTO) GetId() string { if o == nil { var ret string return ret @@ -177,7 +178,7 @@ func (o *Build) GetId() string { // GetIdOk returns a tuple with the Id field value // and a boolean to check if the value has been set. -func (o *Build) GetIdOk() (*string, bool) { +func (o *BuildDTO) GetIdOk() (*string, bool) { if o == nil { return nil, false } @@ -185,12 +186,12 @@ func (o *Build) GetIdOk() (*string, bool) { } // SetId sets field value -func (o *Build) SetId(v string) { +func (o *BuildDTO) SetId(v string) { o.Id = v } // GetImage returns the Image field value if set, zero value otherwise. -func (o *Build) GetImage() string { +func (o *BuildDTO) GetImage() string { if o == nil || IsNil(o.Image) { var ret string return ret @@ -200,7 +201,7 @@ func (o *Build) GetImage() string { // GetImageOk returns a tuple with the Image field value if set, nil otherwise // and a boolean to check if the value has been set. -func (o *Build) GetImageOk() (*string, bool) { +func (o *BuildDTO) GetImageOk() (*string, bool) { if o == nil || IsNil(o.Image) { return nil, false } @@ -208,7 +209,7 @@ func (o *Build) GetImageOk() (*string, bool) { } // HasImage returns a boolean if a field has been set. -func (o *Build) HasImage() bool { +func (o *BuildDTO) HasImage() bool { if o != nil && !IsNil(o.Image) { return true } @@ -217,36 +218,108 @@ func (o *Build) HasImage() bool { } // SetImage gets a reference to the given string and assigns it to the Image field. -func (o *Build) SetImage(v string) { +func (o *BuildDTO) SetImage(v string) { o.Image = &v } -// GetPrebuildId returns the PrebuildId field value -func (o *Build) GetPrebuildId() string { - if o == nil { +// GetLastJob returns the LastJob field value if set, zero value otherwise. +func (o *BuildDTO) GetLastJob() Job { + if o == nil || IsNil(o.LastJob) { + var ret Job + return ret + } + return *o.LastJob +} + +// GetLastJobOk returns a tuple with the LastJob field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *BuildDTO) GetLastJobOk() (*Job, bool) { + if o == nil || IsNil(o.LastJob) { + return nil, false + } + return o.LastJob, true +} + +// HasLastJob returns a boolean if a field has been set. +func (o *BuildDTO) HasLastJob() bool { + if o != nil && !IsNil(o.LastJob) { + return true + } + + return false +} + +// SetLastJob gets a reference to the given Job and assigns it to the LastJob field. +func (o *BuildDTO) SetLastJob(v Job) { + o.LastJob = &v +} + +// GetLastJobId returns the LastJobId field value if set, zero value otherwise. +func (o *BuildDTO) GetLastJobId() string { + if o == nil || IsNil(o.LastJobId) { var ret string return ret } + return *o.LastJobId +} - return o.PrebuildId +// GetLastJobIdOk returns a tuple with the LastJobId field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *BuildDTO) GetLastJobIdOk() (*string, bool) { + if o == nil || IsNil(o.LastJobId) { + return nil, false + } + return o.LastJobId, true } -// GetPrebuildIdOk returns a tuple with the PrebuildId field value +// HasLastJobId returns a boolean if a field has been set. +func (o *BuildDTO) HasLastJobId() bool { + if o != nil && !IsNil(o.LastJobId) { + return true + } + + return false +} + +// SetLastJobId gets a reference to the given string and assigns it to the LastJobId field. +func (o *BuildDTO) SetLastJobId(v string) { + o.LastJobId = &v +} + +// GetPrebuildId returns the PrebuildId field value if set, zero value otherwise. +func (o *BuildDTO) GetPrebuildId() string { + if o == nil || IsNil(o.PrebuildId) { + var ret string + return ret + } + return *o.PrebuildId +} + +// GetPrebuildIdOk returns a tuple with the PrebuildId field value if set, nil otherwise // and a boolean to check if the value has been set. -func (o *Build) GetPrebuildIdOk() (*string, bool) { - if o == nil { +func (o *BuildDTO) GetPrebuildIdOk() (*string, bool) { + if o == nil || IsNil(o.PrebuildId) { return nil, false } - return &o.PrebuildId, true + return o.PrebuildId, true } -// SetPrebuildId sets field value -func (o *Build) SetPrebuildId(v string) { - o.PrebuildId = v +// HasPrebuildId returns a boolean if a field has been set. +func (o *BuildDTO) HasPrebuildId() bool { + if o != nil && !IsNil(o.PrebuildId) { + return true + } + + return false +} + +// SetPrebuildId gets a reference to the given string and assigns it to the PrebuildId field. +func (o *BuildDTO) SetPrebuildId(v string) { + o.PrebuildId = &v } // GetRepository returns the Repository field value -func (o *Build) GetRepository() GitRepository { +func (o *BuildDTO) GetRepository() GitRepository { if o == nil { var ret GitRepository return ret @@ -257,7 +330,7 @@ func (o *Build) GetRepository() GitRepository { // GetRepositoryOk returns a tuple with the Repository field value // and a boolean to check if the value has been set. -func (o *Build) GetRepositoryOk() (*GitRepository, bool) { +func (o *BuildDTO) GetRepositoryOk() (*GitRepository, bool) { if o == nil { return nil, false } @@ -265,14 +338,14 @@ func (o *Build) GetRepositoryOk() (*GitRepository, bool) { } // SetRepository sets field value -func (o *Build) SetRepository(v GitRepository) { +func (o *BuildDTO) SetRepository(v GitRepository) { o.Repository = v } // GetState returns the State field value -func (o *Build) GetState() BuildBuildState { +func (o *BuildDTO) GetState() ResourceState { if o == nil { - var ret BuildBuildState + var ret ResourceState return ret } @@ -281,7 +354,7 @@ func (o *Build) GetState() BuildBuildState { // GetStateOk returns a tuple with the State field value // and a boolean to check if the value has been set. -func (o *Build) GetStateOk() (*BuildBuildState, bool) { +func (o *BuildDTO) GetStateOk() (*ResourceState, bool) { if o == nil { return nil, false } @@ -289,12 +362,12 @@ func (o *Build) GetStateOk() (*BuildBuildState, bool) { } // SetState sets field value -func (o *Build) SetState(v BuildBuildState) { +func (o *BuildDTO) SetState(v ResourceState) { o.State = v } // GetUpdatedAt returns the UpdatedAt field value -func (o *Build) GetUpdatedAt() string { +func (o *BuildDTO) GetUpdatedAt() string { if o == nil { var ret string return ret @@ -305,7 +378,7 @@ func (o *Build) GetUpdatedAt() string { // GetUpdatedAtOk returns a tuple with the UpdatedAt field value // and a boolean to check if the value has been set. -func (o *Build) GetUpdatedAtOk() (*string, bool) { +func (o *BuildDTO) GetUpdatedAtOk() (*string, bool) { if o == nil { return nil, false } @@ -313,12 +386,12 @@ func (o *Build) GetUpdatedAtOk() (*string, bool) { } // SetUpdatedAt sets field value -func (o *Build) SetUpdatedAt(v string) { +func (o *BuildDTO) SetUpdatedAt(v string) { o.UpdatedAt = v } // GetUser returns the User field value if set, zero value otherwise. -func (o *Build) GetUser() string { +func (o *BuildDTO) GetUser() string { if o == nil || IsNil(o.User) { var ret string return ret @@ -328,7 +401,7 @@ func (o *Build) GetUser() string { // GetUserOk returns a tuple with the User field value if set, nil otherwise // and a boolean to check if the value has been set. -func (o *Build) GetUserOk() (*string, bool) { +func (o *BuildDTO) GetUserOk() (*string, bool) { if o == nil || IsNil(o.User) { return nil, false } @@ -336,7 +409,7 @@ func (o *Build) GetUserOk() (*string, bool) { } // HasUser returns a boolean if a field has been set. -func (o *Build) HasUser() bool { +func (o *BuildDTO) HasUser() bool { if o != nil && !IsNil(o.User) { return true } @@ -345,11 +418,11 @@ func (o *Build) HasUser() bool { } // SetUser gets a reference to the given string and assigns it to the User field. -func (o *Build) SetUser(v string) { +func (o *BuildDTO) SetUser(v string) { o.User = &v } -func (o Build) MarshalJSON() ([]byte, error) { +func (o BuildDTO) MarshalJSON() ([]byte, error) { toSerialize, err := o.ToMap() if err != nil { return []byte{}, err @@ -357,7 +430,7 @@ func (o Build) MarshalJSON() ([]byte, error) { return json.Marshal(toSerialize) } -func (o Build) ToMap() (map[string]interface{}, error) { +func (o BuildDTO) ToMap() (map[string]interface{}, error) { toSerialize := map[string]interface{}{} if !IsNil(o.BuildConfig) { toSerialize["buildConfig"] = o.BuildConfig @@ -369,7 +442,15 @@ func (o Build) ToMap() (map[string]interface{}, error) { if !IsNil(o.Image) { toSerialize["image"] = o.Image } - toSerialize["prebuildId"] = o.PrebuildId + if !IsNil(o.LastJob) { + toSerialize["lastJob"] = o.LastJob + } + if !IsNil(o.LastJobId) { + toSerialize["lastJobId"] = o.LastJobId + } + if !IsNil(o.PrebuildId) { + toSerialize["prebuildId"] = o.PrebuildId + } toSerialize["repository"] = o.Repository toSerialize["state"] = o.State toSerialize["updatedAt"] = o.UpdatedAt @@ -379,7 +460,7 @@ func (o Build) ToMap() (map[string]interface{}, error) { return toSerialize, nil } -func (o *Build) UnmarshalJSON(data []byte) (err error) { +func (o *BuildDTO) UnmarshalJSON(data []byte) (err error) { // This validates that all required properties are included in the JSON object // by unmarshalling the object into a generic map with string keys and checking // that every required field exists as a key in the generic map. @@ -388,7 +469,6 @@ func (o *Build) UnmarshalJSON(data []byte) (err error) { "createdAt", "envVars", "id", - "prebuildId", "repository", "state", "updatedAt", @@ -408,53 +488,53 @@ func (o *Build) UnmarshalJSON(data []byte) (err error) { } } - varBuild := _Build{} + varBuildDTO := _BuildDTO{} decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() - err = decoder.Decode(&varBuild) + err = decoder.Decode(&varBuildDTO) if err != nil { return err } - *o = Build(varBuild) + *o = BuildDTO(varBuildDTO) return err } -type NullableBuild struct { - value *Build +type NullableBuildDTO struct { + value *BuildDTO isSet bool } -func (v NullableBuild) Get() *Build { +func (v NullableBuildDTO) Get() *BuildDTO { return v.value } -func (v *NullableBuild) Set(val *Build) { +func (v *NullableBuildDTO) Set(val *BuildDTO) { v.value = val v.isSet = true } -func (v NullableBuild) IsSet() bool { +func (v NullableBuildDTO) IsSet() bool { return v.isSet } -func (v *NullableBuild) Unset() { +func (v *NullableBuildDTO) Unset() { v.value = nil v.isSet = false } -func NewNullableBuild(val *Build) *NullableBuild { - return &NullableBuild{value: val, isSet: true} +func NewNullableBuildDTO(val *BuildDTO) *NullableBuildDTO { + return &NullableBuildDTO{value: val, isSet: true} } -func (v NullableBuild) MarshalJSON() ([]byte, error) { +func (v NullableBuildDTO) MarshalJSON() ([]byte, error) { return json.Marshal(v.value) } -func (v *NullableBuild) UnmarshalJSON(src []byte) error { +func (v *NullableBuildDTO) UnmarshalJSON(src []byte) error { v.isSet = true return json.Unmarshal(src, &v.value) } diff --git a/pkg/apiclient/model_create_build_dto.go b/pkg/apiclient/model_create_build_dto.go index 37e4267d4d..26a45a09b0 100644 --- a/pkg/apiclient/model_create_build_dto.go +++ b/pkg/apiclient/model_create_build_dto.go @@ -21,10 +21,10 @@ var _ MappedNullable = &CreateBuildDTO{} // CreateBuildDTO struct for CreateBuildDTO type CreateBuildDTO struct { - Branch string `json:"branch"` - EnvVars map[string]string `json:"envVars"` - PrebuildId *string `json:"prebuildId,omitempty"` - ProjectConfigName string `json:"projectConfigName"` + Branch string `json:"branch"` + EnvVars map[string]string `json:"envVars"` + PrebuildId *string `json:"prebuildId,omitempty"` + WorkspaceTemplateName string `json:"workspaceTemplateName"` } type _CreateBuildDTO CreateBuildDTO @@ -33,11 +33,11 @@ type _CreateBuildDTO CreateBuildDTO // This constructor will assign default values to properties that have it defined, // and makes sure properties required by API are set, but the set of arguments // will change when the set of required properties is changed -func NewCreateBuildDTO(branch string, envVars map[string]string, projectConfigName string) *CreateBuildDTO { +func NewCreateBuildDTO(branch string, envVars map[string]string, workspaceTemplateName string) *CreateBuildDTO { this := CreateBuildDTO{} this.Branch = branch this.EnvVars = envVars - this.ProjectConfigName = projectConfigName + this.WorkspaceTemplateName = workspaceTemplateName return &this } @@ -129,28 +129,28 @@ func (o *CreateBuildDTO) SetPrebuildId(v string) { o.PrebuildId = &v } -// GetProjectConfigName returns the ProjectConfigName field value -func (o *CreateBuildDTO) GetProjectConfigName() string { +// GetWorkspaceTemplateName returns the WorkspaceTemplateName field value +func (o *CreateBuildDTO) GetWorkspaceTemplateName() string { if o == nil { var ret string return ret } - return o.ProjectConfigName + return o.WorkspaceTemplateName } -// GetProjectConfigNameOk returns a tuple with the ProjectConfigName field value +// GetWorkspaceTemplateNameOk returns a tuple with the WorkspaceTemplateName field value // and a boolean to check if the value has been set. -func (o *CreateBuildDTO) GetProjectConfigNameOk() (*string, bool) { +func (o *CreateBuildDTO) GetWorkspaceTemplateNameOk() (*string, bool) { if o == nil { return nil, false } - return &o.ProjectConfigName, true + return &o.WorkspaceTemplateName, true } -// SetProjectConfigName sets field value -func (o *CreateBuildDTO) SetProjectConfigName(v string) { - o.ProjectConfigName = v +// SetWorkspaceTemplateName sets field value +func (o *CreateBuildDTO) SetWorkspaceTemplateName(v string) { + o.WorkspaceTemplateName = v } func (o CreateBuildDTO) MarshalJSON() ([]byte, error) { @@ -168,7 +168,7 @@ func (o CreateBuildDTO) ToMap() (map[string]interface{}, error) { if !IsNil(o.PrebuildId) { toSerialize["prebuildId"] = o.PrebuildId } - toSerialize["projectConfigName"] = o.ProjectConfigName + toSerialize["workspaceTemplateName"] = o.WorkspaceTemplateName return toSerialize, nil } @@ -179,7 +179,7 @@ func (o *CreateBuildDTO) UnmarshalJSON(data []byte) (err error) { requiredProperties := []string{ "branch", "envVars", - "projectConfigName", + "workspaceTemplateName", } allProperties := make(map[string]interface{}) diff --git a/pkg/apiclient/model_create_project_dto.go b/pkg/apiclient/model_create_project_dto.go deleted file mode 100644 index df7c43ec87..0000000000 --- a/pkg/apiclient/model_create_project_dto.go +++ /dev/null @@ -1,356 +0,0 @@ -/* -Daytona Server API - -Daytona Server API - -API version: v0.0.0-dev -*/ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package apiclient - -import ( - "bytes" - "encoding/json" - "fmt" -) - -// checks if the CreateProjectDTO type satisfies the MappedNullable interface at compile time -var _ MappedNullable = &CreateProjectDTO{} - -// CreateProjectDTO struct for CreateProjectDTO -type CreateProjectDTO struct { - BuildConfig *BuildConfig `json:"buildConfig,omitempty"` - EnvVars map[string]string `json:"envVars"` - GitProviderConfigId *string `json:"gitProviderConfigId,omitempty"` - Image *string `json:"image,omitempty"` - Name string `json:"name"` - Source CreateProjectSourceDTO `json:"source"` - User *string `json:"user,omitempty"` -} - -type _CreateProjectDTO CreateProjectDTO - -// NewCreateProjectDTO instantiates a new CreateProjectDTO object -// This constructor will assign default values to properties that have it defined, -// and makes sure properties required by API are set, but the set of arguments -// will change when the set of required properties is changed -func NewCreateProjectDTO(envVars map[string]string, name string, source CreateProjectSourceDTO) *CreateProjectDTO { - this := CreateProjectDTO{} - this.EnvVars = envVars - this.Name = name - this.Source = source - return &this -} - -// NewCreateProjectDTOWithDefaults instantiates a new CreateProjectDTO object -// This constructor will only assign default values to properties that have it defined, -// but it doesn't guarantee that properties required by API are set -func NewCreateProjectDTOWithDefaults() *CreateProjectDTO { - this := CreateProjectDTO{} - return &this -} - -// GetBuildConfig returns the BuildConfig field value if set, zero value otherwise. -func (o *CreateProjectDTO) GetBuildConfig() BuildConfig { - if o == nil || IsNil(o.BuildConfig) { - var ret BuildConfig - return ret - } - return *o.BuildConfig -} - -// GetBuildConfigOk returns a tuple with the BuildConfig field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *CreateProjectDTO) GetBuildConfigOk() (*BuildConfig, bool) { - if o == nil || IsNil(o.BuildConfig) { - return nil, false - } - return o.BuildConfig, true -} - -// HasBuildConfig returns a boolean if a field has been set. -func (o *CreateProjectDTO) HasBuildConfig() bool { - if o != nil && !IsNil(o.BuildConfig) { - return true - } - - return false -} - -// SetBuildConfig gets a reference to the given BuildConfig and assigns it to the BuildConfig field. -func (o *CreateProjectDTO) SetBuildConfig(v BuildConfig) { - o.BuildConfig = &v -} - -// GetEnvVars returns the EnvVars field value -func (o *CreateProjectDTO) GetEnvVars() map[string]string { - if o == nil { - var ret map[string]string - return ret - } - - return o.EnvVars -} - -// GetEnvVarsOk returns a tuple with the EnvVars field value -// and a boolean to check if the value has been set. -func (o *CreateProjectDTO) GetEnvVarsOk() (*map[string]string, bool) { - if o == nil { - return nil, false - } - return &o.EnvVars, true -} - -// SetEnvVars sets field value -func (o *CreateProjectDTO) SetEnvVars(v map[string]string) { - o.EnvVars = v -} - -// GetGitProviderConfigId returns the GitProviderConfigId field value if set, zero value otherwise. -func (o *CreateProjectDTO) GetGitProviderConfigId() string { - if o == nil || IsNil(o.GitProviderConfigId) { - var ret string - return ret - } - return *o.GitProviderConfigId -} - -// GetGitProviderConfigIdOk returns a tuple with the GitProviderConfigId field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *CreateProjectDTO) GetGitProviderConfigIdOk() (*string, bool) { - if o == nil || IsNil(o.GitProviderConfigId) { - return nil, false - } - return o.GitProviderConfigId, true -} - -// HasGitProviderConfigId returns a boolean if a field has been set. -func (o *CreateProjectDTO) HasGitProviderConfigId() bool { - if o != nil && !IsNil(o.GitProviderConfigId) { - return true - } - - return false -} - -// SetGitProviderConfigId gets a reference to the given string and assigns it to the GitProviderConfigId field. -func (o *CreateProjectDTO) SetGitProviderConfigId(v string) { - o.GitProviderConfigId = &v -} - -// GetImage returns the Image field value if set, zero value otherwise. -func (o *CreateProjectDTO) GetImage() string { - if o == nil || IsNil(o.Image) { - var ret string - return ret - } - return *o.Image -} - -// GetImageOk returns a tuple with the Image field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *CreateProjectDTO) GetImageOk() (*string, bool) { - if o == nil || IsNil(o.Image) { - return nil, false - } - return o.Image, true -} - -// HasImage returns a boolean if a field has been set. -func (o *CreateProjectDTO) HasImage() bool { - if o != nil && !IsNil(o.Image) { - return true - } - - return false -} - -// SetImage gets a reference to the given string and assigns it to the Image field. -func (o *CreateProjectDTO) SetImage(v string) { - o.Image = &v -} - -// GetName returns the Name field value -func (o *CreateProjectDTO) GetName() string { - if o == nil { - var ret string - return ret - } - - return o.Name -} - -// GetNameOk returns a tuple with the Name field value -// and a boolean to check if the value has been set. -func (o *CreateProjectDTO) GetNameOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.Name, true -} - -// SetName sets field value -func (o *CreateProjectDTO) SetName(v string) { - o.Name = v -} - -// GetSource returns the Source field value -func (o *CreateProjectDTO) GetSource() CreateProjectSourceDTO { - if o == nil { - var ret CreateProjectSourceDTO - return ret - } - - return o.Source -} - -// GetSourceOk returns a tuple with the Source field value -// and a boolean to check if the value has been set. -func (o *CreateProjectDTO) GetSourceOk() (*CreateProjectSourceDTO, bool) { - if o == nil { - return nil, false - } - return &o.Source, true -} - -// SetSource sets field value -func (o *CreateProjectDTO) SetSource(v CreateProjectSourceDTO) { - o.Source = v -} - -// GetUser returns the User field value if set, zero value otherwise. -func (o *CreateProjectDTO) GetUser() string { - if o == nil || IsNil(o.User) { - var ret string - return ret - } - return *o.User -} - -// GetUserOk returns a tuple with the User field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *CreateProjectDTO) GetUserOk() (*string, bool) { - if o == nil || IsNil(o.User) { - return nil, false - } - return o.User, true -} - -// HasUser returns a boolean if a field has been set. -func (o *CreateProjectDTO) HasUser() bool { - if o != nil && !IsNil(o.User) { - return true - } - - return false -} - -// SetUser gets a reference to the given string and assigns it to the User field. -func (o *CreateProjectDTO) SetUser(v string) { - o.User = &v -} - -func (o CreateProjectDTO) MarshalJSON() ([]byte, error) { - toSerialize, err := o.ToMap() - if err != nil { - return []byte{}, err - } - return json.Marshal(toSerialize) -} - -func (o CreateProjectDTO) ToMap() (map[string]interface{}, error) { - toSerialize := map[string]interface{}{} - if !IsNil(o.BuildConfig) { - toSerialize["buildConfig"] = o.BuildConfig - } - toSerialize["envVars"] = o.EnvVars - if !IsNil(o.GitProviderConfigId) { - toSerialize["gitProviderConfigId"] = o.GitProviderConfigId - } - if !IsNil(o.Image) { - toSerialize["image"] = o.Image - } - toSerialize["name"] = o.Name - toSerialize["source"] = o.Source - if !IsNil(o.User) { - toSerialize["user"] = o.User - } - return toSerialize, nil -} - -func (o *CreateProjectDTO) UnmarshalJSON(data []byte) (err error) { - // This validates that all required properties are included in the JSON object - // by unmarshalling the object into a generic map with string keys and checking - // that every required field exists as a key in the generic map. - requiredProperties := []string{ - "envVars", - "name", - "source", - } - - allProperties := make(map[string]interface{}) - - err = json.Unmarshal(data, &allProperties) - - if err != nil { - return err - } - - for _, requiredProperty := range requiredProperties { - if _, exists := allProperties[requiredProperty]; !exists { - return fmt.Errorf("no value given for required property %v", requiredProperty) - } - } - - varCreateProjectDTO := _CreateProjectDTO{} - - decoder := json.NewDecoder(bytes.NewReader(data)) - decoder.DisallowUnknownFields() - err = decoder.Decode(&varCreateProjectDTO) - - if err != nil { - return err - } - - *o = CreateProjectDTO(varCreateProjectDTO) - - return err -} - -type NullableCreateProjectDTO struct { - value *CreateProjectDTO - isSet bool -} - -func (v NullableCreateProjectDTO) Get() *CreateProjectDTO { - return v.value -} - -func (v *NullableCreateProjectDTO) Set(val *CreateProjectDTO) { - v.value = val - v.isSet = true -} - -func (v NullableCreateProjectDTO) IsSet() bool { - return v.isSet -} - -func (v *NullableCreateProjectDTO) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableCreateProjectDTO(val *CreateProjectDTO) *NullableCreateProjectDTO { - return &NullableCreateProjectDTO{value: val, isSet: true} -} - -func (v NullableCreateProjectDTO) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableCreateProjectDTO) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/pkg/apiclient/model_create_runner_dto.go b/pkg/apiclient/model_create_runner_dto.go new file mode 100644 index 0000000000..7d80cccbb5 --- /dev/null +++ b/pkg/apiclient/model_create_runner_dto.go @@ -0,0 +1,184 @@ +/* +Daytona Server API + +Daytona Server API + +API version: v0.0.0-dev +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package apiclient + +import ( + "bytes" + "encoding/json" + "fmt" +) + +// checks if the CreateRunnerDTO type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &CreateRunnerDTO{} + +// CreateRunnerDTO struct for CreateRunnerDTO +type CreateRunnerDTO struct { + Id string `json:"id"` + Name string `json:"name"` +} + +type _CreateRunnerDTO CreateRunnerDTO + +// NewCreateRunnerDTO instantiates a new CreateRunnerDTO object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewCreateRunnerDTO(id string, name string) *CreateRunnerDTO { + this := CreateRunnerDTO{} + this.Id = id + this.Name = name + return &this +} + +// NewCreateRunnerDTOWithDefaults instantiates a new CreateRunnerDTO object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewCreateRunnerDTOWithDefaults() *CreateRunnerDTO { + this := CreateRunnerDTO{} + return &this +} + +// GetId returns the Id field value +func (o *CreateRunnerDTO) GetId() string { + if o == nil { + var ret string + return ret + } + + return o.Id +} + +// GetIdOk returns a tuple with the Id field value +// and a boolean to check if the value has been set. +func (o *CreateRunnerDTO) GetIdOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Id, true +} + +// SetId sets field value +func (o *CreateRunnerDTO) SetId(v string) { + o.Id = v +} + +// GetName returns the Name field value +func (o *CreateRunnerDTO) GetName() string { + if o == nil { + var ret string + return ret + } + + return o.Name +} + +// GetNameOk returns a tuple with the Name field value +// and a boolean to check if the value has been set. +func (o *CreateRunnerDTO) GetNameOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Name, true +} + +// SetName sets field value +func (o *CreateRunnerDTO) SetName(v string) { + o.Name = v +} + +func (o CreateRunnerDTO) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o CreateRunnerDTO) ToMap() (map[string]interface{}, error) { + toSerialize := map[string]interface{}{} + toSerialize["id"] = o.Id + toSerialize["name"] = o.Name + return toSerialize, nil +} + +func (o *CreateRunnerDTO) UnmarshalJSON(data []byte) (err error) { + // This validates that all required properties are included in the JSON object + // by unmarshalling the object into a generic map with string keys and checking + // that every required field exists as a key in the generic map. + requiredProperties := []string{ + "id", + "name", + } + + allProperties := make(map[string]interface{}) + + err = json.Unmarshal(data, &allProperties) + + if err != nil { + return err + } + + for _, requiredProperty := range requiredProperties { + if _, exists := allProperties[requiredProperty]; !exists { + return fmt.Errorf("no value given for required property %v", requiredProperty) + } + } + + varCreateRunnerDTO := _CreateRunnerDTO{} + + decoder := json.NewDecoder(bytes.NewReader(data)) + decoder.DisallowUnknownFields() + err = decoder.Decode(&varCreateRunnerDTO) + + if err != nil { + return err + } + + *o = CreateRunnerDTO(varCreateRunnerDTO) + + return err +} + +type NullableCreateRunnerDTO struct { + value *CreateRunnerDTO + isSet bool +} + +func (v NullableCreateRunnerDTO) Get() *CreateRunnerDTO { + return v.value +} + +func (v *NullableCreateRunnerDTO) Set(val *CreateRunnerDTO) { + v.value = val + v.isSet = true +} + +func (v NullableCreateRunnerDTO) IsSet() bool { + return v.isSet +} + +func (v *NullableCreateRunnerDTO) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableCreateRunnerDTO(val *CreateRunnerDTO) *NullableCreateRunnerDTO { + return &NullableCreateRunnerDTO{value: val, isSet: true} +} + +func (v NullableCreateRunnerDTO) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableCreateRunnerDTO) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/pkg/apiclient/model_create_runner_result_dto.go b/pkg/apiclient/model_create_runner_result_dto.go new file mode 100644 index 0000000000..799f0fcd2a --- /dev/null +++ b/pkg/apiclient/model_create_runner_result_dto.go @@ -0,0 +1,248 @@ +/* +Daytona Server API + +Daytona Server API + +API version: v0.0.0-dev +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package apiclient + +import ( + "bytes" + "encoding/json" + "fmt" +) + +// checks if the CreateRunnerResultDTO type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &CreateRunnerResultDTO{} + +// CreateRunnerResultDTO struct for CreateRunnerResultDTO +type CreateRunnerResultDTO struct { + ApiKey string `json:"apiKey"` + Id string `json:"id"` + Metadata *RunnerMetadata `json:"metadata,omitempty"` + Name string `json:"name"` +} + +type _CreateRunnerResultDTO CreateRunnerResultDTO + +// NewCreateRunnerResultDTO instantiates a new CreateRunnerResultDTO object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewCreateRunnerResultDTO(apiKey string, id string, name string) *CreateRunnerResultDTO { + this := CreateRunnerResultDTO{} + this.ApiKey = apiKey + this.Id = id + this.Name = name + return &this +} + +// NewCreateRunnerResultDTOWithDefaults instantiates a new CreateRunnerResultDTO object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewCreateRunnerResultDTOWithDefaults() *CreateRunnerResultDTO { + this := CreateRunnerResultDTO{} + return &this +} + +// GetApiKey returns the ApiKey field value +func (o *CreateRunnerResultDTO) GetApiKey() string { + if o == nil { + var ret string + return ret + } + + return o.ApiKey +} + +// GetApiKeyOk returns a tuple with the ApiKey field value +// and a boolean to check if the value has been set. +func (o *CreateRunnerResultDTO) GetApiKeyOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.ApiKey, true +} + +// SetApiKey sets field value +func (o *CreateRunnerResultDTO) SetApiKey(v string) { + o.ApiKey = v +} + +// GetId returns the Id field value +func (o *CreateRunnerResultDTO) GetId() string { + if o == nil { + var ret string + return ret + } + + return o.Id +} + +// GetIdOk returns a tuple with the Id field value +// and a boolean to check if the value has been set. +func (o *CreateRunnerResultDTO) GetIdOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Id, true +} + +// SetId sets field value +func (o *CreateRunnerResultDTO) SetId(v string) { + o.Id = v +} + +// GetMetadata returns the Metadata field value if set, zero value otherwise. +func (o *CreateRunnerResultDTO) GetMetadata() RunnerMetadata { + if o == nil || IsNil(o.Metadata) { + var ret RunnerMetadata + return ret + } + return *o.Metadata +} + +// GetMetadataOk returns a tuple with the Metadata field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *CreateRunnerResultDTO) GetMetadataOk() (*RunnerMetadata, bool) { + if o == nil || IsNil(o.Metadata) { + return nil, false + } + return o.Metadata, true +} + +// HasMetadata returns a boolean if a field has been set. +func (o *CreateRunnerResultDTO) HasMetadata() bool { + if o != nil && !IsNil(o.Metadata) { + return true + } + + return false +} + +// SetMetadata gets a reference to the given RunnerMetadata and assigns it to the Metadata field. +func (o *CreateRunnerResultDTO) SetMetadata(v RunnerMetadata) { + o.Metadata = &v +} + +// GetName returns the Name field value +func (o *CreateRunnerResultDTO) GetName() string { + if o == nil { + var ret string + return ret + } + + return o.Name +} + +// GetNameOk returns a tuple with the Name field value +// and a boolean to check if the value has been set. +func (o *CreateRunnerResultDTO) GetNameOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Name, true +} + +// SetName sets field value +func (o *CreateRunnerResultDTO) SetName(v string) { + o.Name = v +} + +func (o CreateRunnerResultDTO) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o CreateRunnerResultDTO) ToMap() (map[string]interface{}, error) { + toSerialize := map[string]interface{}{} + toSerialize["apiKey"] = o.ApiKey + toSerialize["id"] = o.Id + if !IsNil(o.Metadata) { + toSerialize["metadata"] = o.Metadata + } + toSerialize["name"] = o.Name + return toSerialize, nil +} + +func (o *CreateRunnerResultDTO) UnmarshalJSON(data []byte) (err error) { + // This validates that all required properties are included in the JSON object + // by unmarshalling the object into a generic map with string keys and checking + // that every required field exists as a key in the generic map. + requiredProperties := []string{ + "apiKey", + "id", + "name", + } + + allProperties := make(map[string]interface{}) + + err = json.Unmarshal(data, &allProperties) + + if err != nil { + return err + } + + for _, requiredProperty := range requiredProperties { + if _, exists := allProperties[requiredProperty]; !exists { + return fmt.Errorf("no value given for required property %v", requiredProperty) + } + } + + varCreateRunnerResultDTO := _CreateRunnerResultDTO{} + + decoder := json.NewDecoder(bytes.NewReader(data)) + decoder.DisallowUnknownFields() + err = decoder.Decode(&varCreateRunnerResultDTO) + + if err != nil { + return err + } + + *o = CreateRunnerResultDTO(varCreateRunnerResultDTO) + + return err +} + +type NullableCreateRunnerResultDTO struct { + value *CreateRunnerResultDTO + isSet bool +} + +func (v NullableCreateRunnerResultDTO) Get() *CreateRunnerResultDTO { + return v.value +} + +func (v *NullableCreateRunnerResultDTO) Set(val *CreateRunnerResultDTO) { + v.value = val + v.isSet = true +} + +func (v NullableCreateRunnerResultDTO) IsSet() bool { + return v.isSet +} + +func (v *NullableCreateRunnerResultDTO) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableCreateRunnerResultDTO(val *CreateRunnerResultDTO) *NullableCreateRunnerResultDTO { + return &NullableCreateRunnerResultDTO{value: val, isSet: true} +} + +func (v NullableCreateRunnerResultDTO) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableCreateRunnerResultDTO) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/pkg/apiclient/model_create_provider_target_dto.go b/pkg/apiclient/model_create_target_config_dto.go similarity index 54% rename from pkg/apiclient/model_create_provider_target_dto.go rename to pkg/apiclient/model_create_target_config_dto.go index acd7ba8273..bb05ee4290 100644 --- a/pkg/apiclient/model_create_provider_target_dto.go +++ b/pkg/apiclient/model_create_target_config_dto.go @@ -16,40 +16,40 @@ import ( "fmt" ) -// checks if the CreateProviderTargetDTO type satisfies the MappedNullable interface at compile time -var _ MappedNullable = &CreateProviderTargetDTO{} +// checks if the CreateTargetConfigDTO type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &CreateTargetConfigDTO{} -// CreateProviderTargetDTO struct for CreateProviderTargetDTO -type CreateProviderTargetDTO struct { - Name string `json:"name"` - Options string `json:"options"` - ProviderInfo ProviderProviderInfo `json:"providerInfo"` +// CreateTargetConfigDTO struct for CreateTargetConfigDTO +type CreateTargetConfigDTO struct { + Name string `json:"name"` + Options string `json:"options"` + ProviderInfo ProviderInfo `json:"providerInfo"` } -type _CreateProviderTargetDTO CreateProviderTargetDTO +type _CreateTargetConfigDTO CreateTargetConfigDTO -// NewCreateProviderTargetDTO instantiates a new CreateProviderTargetDTO object +// NewCreateTargetConfigDTO instantiates a new CreateTargetConfigDTO object // This constructor will assign default values to properties that have it defined, // and makes sure properties required by API are set, but the set of arguments // will change when the set of required properties is changed -func NewCreateProviderTargetDTO(name string, options string, providerInfo ProviderProviderInfo) *CreateProviderTargetDTO { - this := CreateProviderTargetDTO{} +func NewCreateTargetConfigDTO(name string, options string, providerInfo ProviderInfo) *CreateTargetConfigDTO { + this := CreateTargetConfigDTO{} this.Name = name this.Options = options this.ProviderInfo = providerInfo return &this } -// NewCreateProviderTargetDTOWithDefaults instantiates a new CreateProviderTargetDTO object +// NewCreateTargetConfigDTOWithDefaults instantiates a new CreateTargetConfigDTO object // This constructor will only assign default values to properties that have it defined, // but it doesn't guarantee that properties required by API are set -func NewCreateProviderTargetDTOWithDefaults() *CreateProviderTargetDTO { - this := CreateProviderTargetDTO{} +func NewCreateTargetConfigDTOWithDefaults() *CreateTargetConfigDTO { + this := CreateTargetConfigDTO{} return &this } // GetName returns the Name field value -func (o *CreateProviderTargetDTO) GetName() string { +func (o *CreateTargetConfigDTO) GetName() string { if o == nil { var ret string return ret @@ -60,7 +60,7 @@ func (o *CreateProviderTargetDTO) GetName() string { // GetNameOk returns a tuple with the Name field value // and a boolean to check if the value has been set. -func (o *CreateProviderTargetDTO) GetNameOk() (*string, bool) { +func (o *CreateTargetConfigDTO) GetNameOk() (*string, bool) { if o == nil { return nil, false } @@ -68,12 +68,12 @@ func (o *CreateProviderTargetDTO) GetNameOk() (*string, bool) { } // SetName sets field value -func (o *CreateProviderTargetDTO) SetName(v string) { +func (o *CreateTargetConfigDTO) SetName(v string) { o.Name = v } // GetOptions returns the Options field value -func (o *CreateProviderTargetDTO) GetOptions() string { +func (o *CreateTargetConfigDTO) GetOptions() string { if o == nil { var ret string return ret @@ -84,7 +84,7 @@ func (o *CreateProviderTargetDTO) GetOptions() string { // GetOptionsOk returns a tuple with the Options field value // and a boolean to check if the value has been set. -func (o *CreateProviderTargetDTO) GetOptionsOk() (*string, bool) { +func (o *CreateTargetConfigDTO) GetOptionsOk() (*string, bool) { if o == nil { return nil, false } @@ -92,14 +92,14 @@ func (o *CreateProviderTargetDTO) GetOptionsOk() (*string, bool) { } // SetOptions sets field value -func (o *CreateProviderTargetDTO) SetOptions(v string) { +func (o *CreateTargetConfigDTO) SetOptions(v string) { o.Options = v } // GetProviderInfo returns the ProviderInfo field value -func (o *CreateProviderTargetDTO) GetProviderInfo() ProviderProviderInfo { +func (o *CreateTargetConfigDTO) GetProviderInfo() ProviderInfo { if o == nil { - var ret ProviderProviderInfo + var ret ProviderInfo return ret } @@ -108,7 +108,7 @@ func (o *CreateProviderTargetDTO) GetProviderInfo() ProviderProviderInfo { // GetProviderInfoOk returns a tuple with the ProviderInfo field value // and a boolean to check if the value has been set. -func (o *CreateProviderTargetDTO) GetProviderInfoOk() (*ProviderProviderInfo, bool) { +func (o *CreateTargetConfigDTO) GetProviderInfoOk() (*ProviderInfo, bool) { if o == nil { return nil, false } @@ -116,11 +116,11 @@ func (o *CreateProviderTargetDTO) GetProviderInfoOk() (*ProviderProviderInfo, bo } // SetProviderInfo sets field value -func (o *CreateProviderTargetDTO) SetProviderInfo(v ProviderProviderInfo) { +func (o *CreateTargetConfigDTO) SetProviderInfo(v ProviderInfo) { o.ProviderInfo = v } -func (o CreateProviderTargetDTO) MarshalJSON() ([]byte, error) { +func (o CreateTargetConfigDTO) MarshalJSON() ([]byte, error) { toSerialize, err := o.ToMap() if err != nil { return []byte{}, err @@ -128,7 +128,7 @@ func (o CreateProviderTargetDTO) MarshalJSON() ([]byte, error) { return json.Marshal(toSerialize) } -func (o CreateProviderTargetDTO) ToMap() (map[string]interface{}, error) { +func (o CreateTargetConfigDTO) ToMap() (map[string]interface{}, error) { toSerialize := map[string]interface{}{} toSerialize["name"] = o.Name toSerialize["options"] = o.Options @@ -136,7 +136,7 @@ func (o CreateProviderTargetDTO) ToMap() (map[string]interface{}, error) { return toSerialize, nil } -func (o *CreateProviderTargetDTO) UnmarshalJSON(data []byte) (err error) { +func (o *CreateTargetConfigDTO) UnmarshalJSON(data []byte) (err error) { // This validates that all required properties are included in the JSON object // by unmarshalling the object into a generic map with string keys and checking // that every required field exists as a key in the generic map. @@ -160,53 +160,53 @@ func (o *CreateProviderTargetDTO) UnmarshalJSON(data []byte) (err error) { } } - varCreateProviderTargetDTO := _CreateProviderTargetDTO{} + varCreateTargetConfigDTO := _CreateTargetConfigDTO{} decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() - err = decoder.Decode(&varCreateProviderTargetDTO) + err = decoder.Decode(&varCreateTargetConfigDTO) if err != nil { return err } - *o = CreateProviderTargetDTO(varCreateProviderTargetDTO) + *o = CreateTargetConfigDTO(varCreateTargetConfigDTO) return err } -type NullableCreateProviderTargetDTO struct { - value *CreateProviderTargetDTO +type NullableCreateTargetConfigDTO struct { + value *CreateTargetConfigDTO isSet bool } -func (v NullableCreateProviderTargetDTO) Get() *CreateProviderTargetDTO { +func (v NullableCreateTargetConfigDTO) Get() *CreateTargetConfigDTO { return v.value } -func (v *NullableCreateProviderTargetDTO) Set(val *CreateProviderTargetDTO) { +func (v *NullableCreateTargetConfigDTO) Set(val *CreateTargetConfigDTO) { v.value = val v.isSet = true } -func (v NullableCreateProviderTargetDTO) IsSet() bool { +func (v NullableCreateTargetConfigDTO) IsSet() bool { return v.isSet } -func (v *NullableCreateProviderTargetDTO) Unset() { +func (v *NullableCreateTargetConfigDTO) Unset() { v.value = nil v.isSet = false } -func NewNullableCreateProviderTargetDTO(val *CreateProviderTargetDTO) *NullableCreateProviderTargetDTO { - return &NullableCreateProviderTargetDTO{value: val, isSet: true} +func NewNullableCreateTargetConfigDTO(val *CreateTargetConfigDTO) *NullableCreateTargetConfigDTO { + return &NullableCreateTargetConfigDTO{value: val, isSet: true} } -func (v NullableCreateProviderTargetDTO) MarshalJSON() ([]byte, error) { +func (v NullableCreateTargetConfigDTO) MarshalJSON() ([]byte, error) { return json.Marshal(v.value) } -func (v *NullableCreateProviderTargetDTO) UnmarshalJSON(src []byte) error { +func (v *NullableCreateTargetConfigDTO) UnmarshalJSON(src []byte) error { v.isSet = true return json.Unmarshal(src, &v.value) } diff --git a/pkg/apiclient/model_create_target_dto.go b/pkg/apiclient/model_create_target_dto.go new file mode 100644 index 0000000000..6730a0e8cd --- /dev/null +++ b/pkg/apiclient/model_create_target_dto.go @@ -0,0 +1,212 @@ +/* +Daytona Server API + +Daytona Server API + +API version: v0.0.0-dev +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package apiclient + +import ( + "bytes" + "encoding/json" + "fmt" +) + +// checks if the CreateTargetDTO type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &CreateTargetDTO{} + +// CreateTargetDTO struct for CreateTargetDTO +type CreateTargetDTO struct { + Id string `json:"id"` + Name string `json:"name"` + TargetConfigId string `json:"targetConfigId"` +} + +type _CreateTargetDTO CreateTargetDTO + +// NewCreateTargetDTO instantiates a new CreateTargetDTO object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewCreateTargetDTO(id string, name string, targetConfigId string) *CreateTargetDTO { + this := CreateTargetDTO{} + this.Id = id + this.Name = name + this.TargetConfigId = targetConfigId + return &this +} + +// NewCreateTargetDTOWithDefaults instantiates a new CreateTargetDTO object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewCreateTargetDTOWithDefaults() *CreateTargetDTO { + this := CreateTargetDTO{} + return &this +} + +// GetId returns the Id field value +func (o *CreateTargetDTO) GetId() string { + if o == nil { + var ret string + return ret + } + + return o.Id +} + +// GetIdOk returns a tuple with the Id field value +// and a boolean to check if the value has been set. +func (o *CreateTargetDTO) GetIdOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Id, true +} + +// SetId sets field value +func (o *CreateTargetDTO) SetId(v string) { + o.Id = v +} + +// GetName returns the Name field value +func (o *CreateTargetDTO) GetName() string { + if o == nil { + var ret string + return ret + } + + return o.Name +} + +// GetNameOk returns a tuple with the Name field value +// and a boolean to check if the value has been set. +func (o *CreateTargetDTO) GetNameOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Name, true +} + +// SetName sets field value +func (o *CreateTargetDTO) SetName(v string) { + o.Name = v +} + +// GetTargetConfigId returns the TargetConfigId field value +func (o *CreateTargetDTO) GetTargetConfigId() string { + if o == nil { + var ret string + return ret + } + + return o.TargetConfigId +} + +// GetTargetConfigIdOk returns a tuple with the TargetConfigId field value +// and a boolean to check if the value has been set. +func (o *CreateTargetDTO) GetTargetConfigIdOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.TargetConfigId, true +} + +// SetTargetConfigId sets field value +func (o *CreateTargetDTO) SetTargetConfigId(v string) { + o.TargetConfigId = v +} + +func (o CreateTargetDTO) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o CreateTargetDTO) ToMap() (map[string]interface{}, error) { + toSerialize := map[string]interface{}{} + toSerialize["id"] = o.Id + toSerialize["name"] = o.Name + toSerialize["targetConfigId"] = o.TargetConfigId + return toSerialize, nil +} + +func (o *CreateTargetDTO) UnmarshalJSON(data []byte) (err error) { + // This validates that all required properties are included in the JSON object + // by unmarshalling the object into a generic map with string keys and checking + // that every required field exists as a key in the generic map. + requiredProperties := []string{ + "id", + "name", + "targetConfigId", + } + + allProperties := make(map[string]interface{}) + + err = json.Unmarshal(data, &allProperties) + + if err != nil { + return err + } + + for _, requiredProperty := range requiredProperties { + if _, exists := allProperties[requiredProperty]; !exists { + return fmt.Errorf("no value given for required property %v", requiredProperty) + } + } + + varCreateTargetDTO := _CreateTargetDTO{} + + decoder := json.NewDecoder(bytes.NewReader(data)) + decoder.DisallowUnknownFields() + err = decoder.Decode(&varCreateTargetDTO) + + if err != nil { + return err + } + + *o = CreateTargetDTO(varCreateTargetDTO) + + return err +} + +type NullableCreateTargetDTO struct { + value *CreateTargetDTO + isSet bool +} + +func (v NullableCreateTargetDTO) Get() *CreateTargetDTO { + return v.value +} + +func (v *NullableCreateTargetDTO) Set(val *CreateTargetDTO) { + v.value = val + v.isSet = true +} + +func (v NullableCreateTargetDTO) IsSet() bool { + return v.isSet +} + +func (v *NullableCreateTargetDTO) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableCreateTargetDTO(val *CreateTargetDTO) *NullableCreateTargetDTO { + return &NullableCreateTargetDTO{value: val, isSet: true} +} + +func (v NullableCreateTargetDTO) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableCreateTargetDTO) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/pkg/apiclient/model_create_workspace_dto.go b/pkg/apiclient/model_create_workspace_dto.go index 5392ad6fb1..6cecf18ff9 100644 --- a/pkg/apiclient/model_create_workspace_dto.go +++ b/pkg/apiclient/model_create_workspace_dto.go @@ -21,10 +21,16 @@ var _ MappedNullable = &CreateWorkspaceDTO{} // CreateWorkspaceDTO struct for CreateWorkspaceDTO type CreateWorkspaceDTO struct { - Id string `json:"id"` - Name string `json:"name"` - Projects []CreateProjectDTO `json:"projects"` - Target string `json:"target"` + BuildConfig *BuildConfig `json:"buildConfig,omitempty"` + EnvVars map[string]string `json:"envVars"` + GitProviderConfigId *string `json:"gitProviderConfigId,omitempty"` + Id string `json:"id"` + Image *string `json:"image,omitempty"` + Labels map[string]string `json:"labels"` + Name string `json:"name"` + Source CreateWorkspaceSourceDTO `json:"source"` + TargetId string `json:"targetId"` + User *string `json:"user,omitempty"` } type _CreateWorkspaceDTO CreateWorkspaceDTO @@ -33,12 +39,14 @@ type _CreateWorkspaceDTO CreateWorkspaceDTO // This constructor will assign default values to properties that have it defined, // and makes sure properties required by API are set, but the set of arguments // will change when the set of required properties is changed -func NewCreateWorkspaceDTO(id string, name string, projects []CreateProjectDTO, target string) *CreateWorkspaceDTO { +func NewCreateWorkspaceDTO(envVars map[string]string, id string, labels map[string]string, name string, source CreateWorkspaceSourceDTO, targetId string) *CreateWorkspaceDTO { this := CreateWorkspaceDTO{} + this.EnvVars = envVars this.Id = id + this.Labels = labels this.Name = name - this.Projects = projects - this.Target = target + this.Source = source + this.TargetId = targetId return &this } @@ -50,6 +58,94 @@ func NewCreateWorkspaceDTOWithDefaults() *CreateWorkspaceDTO { return &this } +// GetBuildConfig returns the BuildConfig field value if set, zero value otherwise. +func (o *CreateWorkspaceDTO) GetBuildConfig() BuildConfig { + if o == nil || IsNil(o.BuildConfig) { + var ret BuildConfig + return ret + } + return *o.BuildConfig +} + +// GetBuildConfigOk returns a tuple with the BuildConfig field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *CreateWorkspaceDTO) GetBuildConfigOk() (*BuildConfig, bool) { + if o == nil || IsNil(o.BuildConfig) { + return nil, false + } + return o.BuildConfig, true +} + +// HasBuildConfig returns a boolean if a field has been set. +func (o *CreateWorkspaceDTO) HasBuildConfig() bool { + if o != nil && !IsNil(o.BuildConfig) { + return true + } + + return false +} + +// SetBuildConfig gets a reference to the given BuildConfig and assigns it to the BuildConfig field. +func (o *CreateWorkspaceDTO) SetBuildConfig(v BuildConfig) { + o.BuildConfig = &v +} + +// GetEnvVars returns the EnvVars field value +func (o *CreateWorkspaceDTO) GetEnvVars() map[string]string { + if o == nil { + var ret map[string]string + return ret + } + + return o.EnvVars +} + +// GetEnvVarsOk returns a tuple with the EnvVars field value +// and a boolean to check if the value has been set. +func (o *CreateWorkspaceDTO) GetEnvVarsOk() (*map[string]string, bool) { + if o == nil { + return nil, false + } + return &o.EnvVars, true +} + +// SetEnvVars sets field value +func (o *CreateWorkspaceDTO) SetEnvVars(v map[string]string) { + o.EnvVars = v +} + +// GetGitProviderConfigId returns the GitProviderConfigId field value if set, zero value otherwise. +func (o *CreateWorkspaceDTO) GetGitProviderConfigId() string { + if o == nil || IsNil(o.GitProviderConfigId) { + var ret string + return ret + } + return *o.GitProviderConfigId +} + +// GetGitProviderConfigIdOk returns a tuple with the GitProviderConfigId field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *CreateWorkspaceDTO) GetGitProviderConfigIdOk() (*string, bool) { + if o == nil || IsNil(o.GitProviderConfigId) { + return nil, false + } + return o.GitProviderConfigId, true +} + +// HasGitProviderConfigId returns a boolean if a field has been set. +func (o *CreateWorkspaceDTO) HasGitProviderConfigId() bool { + if o != nil && !IsNil(o.GitProviderConfigId) { + return true + } + + return false +} + +// SetGitProviderConfigId gets a reference to the given string and assigns it to the GitProviderConfigId field. +func (o *CreateWorkspaceDTO) SetGitProviderConfigId(v string) { + o.GitProviderConfigId = &v +} + // GetId returns the Id field value func (o *CreateWorkspaceDTO) GetId() string { if o == nil { @@ -74,6 +170,62 @@ func (o *CreateWorkspaceDTO) SetId(v string) { o.Id = v } +// GetImage returns the Image field value if set, zero value otherwise. +func (o *CreateWorkspaceDTO) GetImage() string { + if o == nil || IsNil(o.Image) { + var ret string + return ret + } + return *o.Image +} + +// GetImageOk returns a tuple with the Image field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *CreateWorkspaceDTO) GetImageOk() (*string, bool) { + if o == nil || IsNil(o.Image) { + return nil, false + } + return o.Image, true +} + +// HasImage returns a boolean if a field has been set. +func (o *CreateWorkspaceDTO) HasImage() bool { + if o != nil && !IsNil(o.Image) { + return true + } + + return false +} + +// SetImage gets a reference to the given string and assigns it to the Image field. +func (o *CreateWorkspaceDTO) SetImage(v string) { + o.Image = &v +} + +// GetLabels returns the Labels field value +func (o *CreateWorkspaceDTO) GetLabels() map[string]string { + if o == nil { + var ret map[string]string + return ret + } + + return o.Labels +} + +// GetLabelsOk returns a tuple with the Labels field value +// and a boolean to check if the value has been set. +func (o *CreateWorkspaceDTO) GetLabelsOk() (*map[string]string, bool) { + if o == nil { + return nil, false + } + return &o.Labels, true +} + +// SetLabels sets field value +func (o *CreateWorkspaceDTO) SetLabels(v map[string]string) { + o.Labels = v +} + // GetName returns the Name field value func (o *CreateWorkspaceDTO) GetName() string { if o == nil { @@ -98,52 +250,84 @@ func (o *CreateWorkspaceDTO) SetName(v string) { o.Name = v } -// GetProjects returns the Projects field value -func (o *CreateWorkspaceDTO) GetProjects() []CreateProjectDTO { +// GetSource returns the Source field value +func (o *CreateWorkspaceDTO) GetSource() CreateWorkspaceSourceDTO { if o == nil { - var ret []CreateProjectDTO + var ret CreateWorkspaceSourceDTO return ret } - return o.Projects + return o.Source } -// GetProjectsOk returns a tuple with the Projects field value +// GetSourceOk returns a tuple with the Source field value // and a boolean to check if the value has been set. -func (o *CreateWorkspaceDTO) GetProjectsOk() ([]CreateProjectDTO, bool) { +func (o *CreateWorkspaceDTO) GetSourceOk() (*CreateWorkspaceSourceDTO, bool) { if o == nil { return nil, false } - return o.Projects, true + return &o.Source, true } -// SetProjects sets field value -func (o *CreateWorkspaceDTO) SetProjects(v []CreateProjectDTO) { - o.Projects = v +// SetSource sets field value +func (o *CreateWorkspaceDTO) SetSource(v CreateWorkspaceSourceDTO) { + o.Source = v } -// GetTarget returns the Target field value -func (o *CreateWorkspaceDTO) GetTarget() string { +// GetTargetId returns the TargetId field value +func (o *CreateWorkspaceDTO) GetTargetId() string { if o == nil { var ret string return ret } - return o.Target + return o.TargetId } -// GetTargetOk returns a tuple with the Target field value +// GetTargetIdOk returns a tuple with the TargetId field value // and a boolean to check if the value has been set. -func (o *CreateWorkspaceDTO) GetTargetOk() (*string, bool) { +func (o *CreateWorkspaceDTO) GetTargetIdOk() (*string, bool) { if o == nil { return nil, false } - return &o.Target, true + return &o.TargetId, true } -// SetTarget sets field value -func (o *CreateWorkspaceDTO) SetTarget(v string) { - o.Target = v +// SetTargetId sets field value +func (o *CreateWorkspaceDTO) SetTargetId(v string) { + o.TargetId = v +} + +// GetUser returns the User field value if set, zero value otherwise. +func (o *CreateWorkspaceDTO) GetUser() string { + if o == nil || IsNil(o.User) { + var ret string + return ret + } + return *o.User +} + +// GetUserOk returns a tuple with the User field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *CreateWorkspaceDTO) GetUserOk() (*string, bool) { + if o == nil || IsNil(o.User) { + return nil, false + } + return o.User, true +} + +// HasUser returns a boolean if a field has been set. +func (o *CreateWorkspaceDTO) HasUser() bool { + if o != nil && !IsNil(o.User) { + return true + } + + return false +} + +// SetUser gets a reference to the given string and assigns it to the User field. +func (o *CreateWorkspaceDTO) SetUser(v string) { + o.User = &v } func (o CreateWorkspaceDTO) MarshalJSON() ([]byte, error) { @@ -156,10 +340,24 @@ func (o CreateWorkspaceDTO) MarshalJSON() ([]byte, error) { func (o CreateWorkspaceDTO) ToMap() (map[string]interface{}, error) { toSerialize := map[string]interface{}{} + if !IsNil(o.BuildConfig) { + toSerialize["buildConfig"] = o.BuildConfig + } + toSerialize["envVars"] = o.EnvVars + if !IsNil(o.GitProviderConfigId) { + toSerialize["gitProviderConfigId"] = o.GitProviderConfigId + } toSerialize["id"] = o.Id + if !IsNil(o.Image) { + toSerialize["image"] = o.Image + } + toSerialize["labels"] = o.Labels toSerialize["name"] = o.Name - toSerialize["projects"] = o.Projects - toSerialize["target"] = o.Target + toSerialize["source"] = o.Source + toSerialize["targetId"] = o.TargetId + if !IsNil(o.User) { + toSerialize["user"] = o.User + } return toSerialize, nil } @@ -168,10 +366,12 @@ func (o *CreateWorkspaceDTO) UnmarshalJSON(data []byte) (err error) { // by unmarshalling the object into a generic map with string keys and checking // that every required field exists as a key in the generic map. requiredProperties := []string{ + "envVars", "id", + "labels", "name", - "projects", - "target", + "source", + "targetId", } allProperties := make(map[string]interface{}) diff --git a/pkg/apiclient/model_create_project_source_dto.go b/pkg/apiclient/model_create_workspace_source_dto.go similarity index 53% rename from pkg/apiclient/model_create_project_source_dto.go rename to pkg/apiclient/model_create_workspace_source_dto.go index b2c4c38bb6..00ae0684a0 100644 --- a/pkg/apiclient/model_create_project_source_dto.go +++ b/pkg/apiclient/model_create_workspace_source_dto.go @@ -16,36 +16,36 @@ import ( "fmt" ) -// checks if the CreateProjectSourceDTO type satisfies the MappedNullable interface at compile time -var _ MappedNullable = &CreateProjectSourceDTO{} +// checks if the CreateWorkspaceSourceDTO type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &CreateWorkspaceSourceDTO{} -// CreateProjectSourceDTO struct for CreateProjectSourceDTO -type CreateProjectSourceDTO struct { +// CreateWorkspaceSourceDTO struct for CreateWorkspaceSourceDTO +type CreateWorkspaceSourceDTO struct { Repository GitRepository `json:"repository"` } -type _CreateProjectSourceDTO CreateProjectSourceDTO +type _CreateWorkspaceSourceDTO CreateWorkspaceSourceDTO -// NewCreateProjectSourceDTO instantiates a new CreateProjectSourceDTO object +// NewCreateWorkspaceSourceDTO instantiates a new CreateWorkspaceSourceDTO object // This constructor will assign default values to properties that have it defined, // and makes sure properties required by API are set, but the set of arguments // will change when the set of required properties is changed -func NewCreateProjectSourceDTO(repository GitRepository) *CreateProjectSourceDTO { - this := CreateProjectSourceDTO{} +func NewCreateWorkspaceSourceDTO(repository GitRepository) *CreateWorkspaceSourceDTO { + this := CreateWorkspaceSourceDTO{} this.Repository = repository return &this } -// NewCreateProjectSourceDTOWithDefaults instantiates a new CreateProjectSourceDTO object +// NewCreateWorkspaceSourceDTOWithDefaults instantiates a new CreateWorkspaceSourceDTO object // This constructor will only assign default values to properties that have it defined, // but it doesn't guarantee that properties required by API are set -func NewCreateProjectSourceDTOWithDefaults() *CreateProjectSourceDTO { - this := CreateProjectSourceDTO{} +func NewCreateWorkspaceSourceDTOWithDefaults() *CreateWorkspaceSourceDTO { + this := CreateWorkspaceSourceDTO{} return &this } // GetRepository returns the Repository field value -func (o *CreateProjectSourceDTO) GetRepository() GitRepository { +func (o *CreateWorkspaceSourceDTO) GetRepository() GitRepository { if o == nil { var ret GitRepository return ret @@ -56,7 +56,7 @@ func (o *CreateProjectSourceDTO) GetRepository() GitRepository { // GetRepositoryOk returns a tuple with the Repository field value // and a boolean to check if the value has been set. -func (o *CreateProjectSourceDTO) GetRepositoryOk() (*GitRepository, bool) { +func (o *CreateWorkspaceSourceDTO) GetRepositoryOk() (*GitRepository, bool) { if o == nil { return nil, false } @@ -64,11 +64,11 @@ func (o *CreateProjectSourceDTO) GetRepositoryOk() (*GitRepository, bool) { } // SetRepository sets field value -func (o *CreateProjectSourceDTO) SetRepository(v GitRepository) { +func (o *CreateWorkspaceSourceDTO) SetRepository(v GitRepository) { o.Repository = v } -func (o CreateProjectSourceDTO) MarshalJSON() ([]byte, error) { +func (o CreateWorkspaceSourceDTO) MarshalJSON() ([]byte, error) { toSerialize, err := o.ToMap() if err != nil { return []byte{}, err @@ -76,13 +76,13 @@ func (o CreateProjectSourceDTO) MarshalJSON() ([]byte, error) { return json.Marshal(toSerialize) } -func (o CreateProjectSourceDTO) ToMap() (map[string]interface{}, error) { +func (o CreateWorkspaceSourceDTO) ToMap() (map[string]interface{}, error) { toSerialize := map[string]interface{}{} toSerialize["repository"] = o.Repository return toSerialize, nil } -func (o *CreateProjectSourceDTO) UnmarshalJSON(data []byte) (err error) { +func (o *CreateWorkspaceSourceDTO) UnmarshalJSON(data []byte) (err error) { // This validates that all required properties are included in the JSON object // by unmarshalling the object into a generic map with string keys and checking // that every required field exists as a key in the generic map. @@ -104,53 +104,53 @@ func (o *CreateProjectSourceDTO) UnmarshalJSON(data []byte) (err error) { } } - varCreateProjectSourceDTO := _CreateProjectSourceDTO{} + varCreateWorkspaceSourceDTO := _CreateWorkspaceSourceDTO{} decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() - err = decoder.Decode(&varCreateProjectSourceDTO) + err = decoder.Decode(&varCreateWorkspaceSourceDTO) if err != nil { return err } - *o = CreateProjectSourceDTO(varCreateProjectSourceDTO) + *o = CreateWorkspaceSourceDTO(varCreateWorkspaceSourceDTO) return err } -type NullableCreateProjectSourceDTO struct { - value *CreateProjectSourceDTO +type NullableCreateWorkspaceSourceDTO struct { + value *CreateWorkspaceSourceDTO isSet bool } -func (v NullableCreateProjectSourceDTO) Get() *CreateProjectSourceDTO { +func (v NullableCreateWorkspaceSourceDTO) Get() *CreateWorkspaceSourceDTO { return v.value } -func (v *NullableCreateProjectSourceDTO) Set(val *CreateProjectSourceDTO) { +func (v *NullableCreateWorkspaceSourceDTO) Set(val *CreateWorkspaceSourceDTO) { v.value = val v.isSet = true } -func (v NullableCreateProjectSourceDTO) IsSet() bool { +func (v NullableCreateWorkspaceSourceDTO) IsSet() bool { return v.isSet } -func (v *NullableCreateProjectSourceDTO) Unset() { +func (v *NullableCreateWorkspaceSourceDTO) Unset() { v.value = nil v.isSet = false } -func NewNullableCreateProjectSourceDTO(val *CreateProjectSourceDTO) *NullableCreateProjectSourceDTO { - return &NullableCreateProjectSourceDTO{value: val, isSet: true} +func NewNullableCreateWorkspaceSourceDTO(val *CreateWorkspaceSourceDTO) *NullableCreateWorkspaceSourceDTO { + return &NullableCreateWorkspaceSourceDTO{value: val, isSet: true} } -func (v NullableCreateProjectSourceDTO) MarshalJSON() ([]byte, error) { +func (v NullableCreateWorkspaceSourceDTO) MarshalJSON() ([]byte, error) { return json.Marshal(v.value) } -func (v *NullableCreateProjectSourceDTO) UnmarshalJSON(src []byte) error { +func (v *NullableCreateWorkspaceSourceDTO) UnmarshalJSON(src []byte) error { v.isSet = true return json.Unmarshal(src, &v.value) } diff --git a/pkg/apiclient/model_create_project_config_dto.go b/pkg/apiclient/model_create_workspace_template_dto.go similarity index 64% rename from pkg/apiclient/model_create_project_config_dto.go rename to pkg/apiclient/model_create_workspace_template_dto.go index 0de5ca203e..6ffeb9b780 100644 --- a/pkg/apiclient/model_create_project_config_dto.go +++ b/pkg/apiclient/model_create_workspace_template_dto.go @@ -16,11 +16,11 @@ import ( "fmt" ) -// checks if the CreateProjectConfigDTO type satisfies the MappedNullable interface at compile time -var _ MappedNullable = &CreateProjectConfigDTO{} +// checks if the CreateWorkspaceTemplateDTO type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &CreateWorkspaceTemplateDTO{} -// CreateProjectConfigDTO struct for CreateProjectConfigDTO -type CreateProjectConfigDTO struct { +// CreateWorkspaceTemplateDTO struct for CreateWorkspaceTemplateDTO +type CreateWorkspaceTemplateDTO struct { BuildConfig *BuildConfig `json:"buildConfig,omitempty"` EnvVars map[string]string `json:"envVars"` GitProviderConfigId *string `json:"gitProviderConfigId,omitempty"` @@ -30,30 +30,30 @@ type CreateProjectConfigDTO struct { User *string `json:"user,omitempty"` } -type _CreateProjectConfigDTO CreateProjectConfigDTO +type _CreateWorkspaceTemplateDTO CreateWorkspaceTemplateDTO -// NewCreateProjectConfigDTO instantiates a new CreateProjectConfigDTO object +// NewCreateWorkspaceTemplateDTO instantiates a new CreateWorkspaceTemplateDTO object // This constructor will assign default values to properties that have it defined, // and makes sure properties required by API are set, but the set of arguments // will change when the set of required properties is changed -func NewCreateProjectConfigDTO(envVars map[string]string, name string, repositoryUrl string) *CreateProjectConfigDTO { - this := CreateProjectConfigDTO{} +func NewCreateWorkspaceTemplateDTO(envVars map[string]string, name string, repositoryUrl string) *CreateWorkspaceTemplateDTO { + this := CreateWorkspaceTemplateDTO{} this.EnvVars = envVars this.Name = name this.RepositoryUrl = repositoryUrl return &this } -// NewCreateProjectConfigDTOWithDefaults instantiates a new CreateProjectConfigDTO object +// NewCreateWorkspaceTemplateDTOWithDefaults instantiates a new CreateWorkspaceTemplateDTO object // This constructor will only assign default values to properties that have it defined, // but it doesn't guarantee that properties required by API are set -func NewCreateProjectConfigDTOWithDefaults() *CreateProjectConfigDTO { - this := CreateProjectConfigDTO{} +func NewCreateWorkspaceTemplateDTOWithDefaults() *CreateWorkspaceTemplateDTO { + this := CreateWorkspaceTemplateDTO{} return &this } // GetBuildConfig returns the BuildConfig field value if set, zero value otherwise. -func (o *CreateProjectConfigDTO) GetBuildConfig() BuildConfig { +func (o *CreateWorkspaceTemplateDTO) GetBuildConfig() BuildConfig { if o == nil || IsNil(o.BuildConfig) { var ret BuildConfig return ret @@ -63,7 +63,7 @@ func (o *CreateProjectConfigDTO) GetBuildConfig() BuildConfig { // GetBuildConfigOk returns a tuple with the BuildConfig field value if set, nil otherwise // and a boolean to check if the value has been set. -func (o *CreateProjectConfigDTO) GetBuildConfigOk() (*BuildConfig, bool) { +func (o *CreateWorkspaceTemplateDTO) GetBuildConfigOk() (*BuildConfig, bool) { if o == nil || IsNil(o.BuildConfig) { return nil, false } @@ -71,7 +71,7 @@ func (o *CreateProjectConfigDTO) GetBuildConfigOk() (*BuildConfig, bool) { } // HasBuildConfig returns a boolean if a field has been set. -func (o *CreateProjectConfigDTO) HasBuildConfig() bool { +func (o *CreateWorkspaceTemplateDTO) HasBuildConfig() bool { if o != nil && !IsNil(o.BuildConfig) { return true } @@ -80,12 +80,12 @@ func (o *CreateProjectConfigDTO) HasBuildConfig() bool { } // SetBuildConfig gets a reference to the given BuildConfig and assigns it to the BuildConfig field. -func (o *CreateProjectConfigDTO) SetBuildConfig(v BuildConfig) { +func (o *CreateWorkspaceTemplateDTO) SetBuildConfig(v BuildConfig) { o.BuildConfig = &v } // GetEnvVars returns the EnvVars field value -func (o *CreateProjectConfigDTO) GetEnvVars() map[string]string { +func (o *CreateWorkspaceTemplateDTO) GetEnvVars() map[string]string { if o == nil { var ret map[string]string return ret @@ -96,7 +96,7 @@ func (o *CreateProjectConfigDTO) GetEnvVars() map[string]string { // GetEnvVarsOk returns a tuple with the EnvVars field value // and a boolean to check if the value has been set. -func (o *CreateProjectConfigDTO) GetEnvVarsOk() (*map[string]string, bool) { +func (o *CreateWorkspaceTemplateDTO) GetEnvVarsOk() (*map[string]string, bool) { if o == nil { return nil, false } @@ -104,12 +104,12 @@ func (o *CreateProjectConfigDTO) GetEnvVarsOk() (*map[string]string, bool) { } // SetEnvVars sets field value -func (o *CreateProjectConfigDTO) SetEnvVars(v map[string]string) { +func (o *CreateWorkspaceTemplateDTO) SetEnvVars(v map[string]string) { o.EnvVars = v } // GetGitProviderConfigId returns the GitProviderConfigId field value if set, zero value otherwise. -func (o *CreateProjectConfigDTO) GetGitProviderConfigId() string { +func (o *CreateWorkspaceTemplateDTO) GetGitProviderConfigId() string { if o == nil || IsNil(o.GitProviderConfigId) { var ret string return ret @@ -119,7 +119,7 @@ func (o *CreateProjectConfigDTO) GetGitProviderConfigId() string { // GetGitProviderConfigIdOk returns a tuple with the GitProviderConfigId field value if set, nil otherwise // and a boolean to check if the value has been set. -func (o *CreateProjectConfigDTO) GetGitProviderConfigIdOk() (*string, bool) { +func (o *CreateWorkspaceTemplateDTO) GetGitProviderConfigIdOk() (*string, bool) { if o == nil || IsNil(o.GitProviderConfigId) { return nil, false } @@ -127,7 +127,7 @@ func (o *CreateProjectConfigDTO) GetGitProviderConfigIdOk() (*string, bool) { } // HasGitProviderConfigId returns a boolean if a field has been set. -func (o *CreateProjectConfigDTO) HasGitProviderConfigId() bool { +func (o *CreateWorkspaceTemplateDTO) HasGitProviderConfigId() bool { if o != nil && !IsNil(o.GitProviderConfigId) { return true } @@ -136,12 +136,12 @@ func (o *CreateProjectConfigDTO) HasGitProviderConfigId() bool { } // SetGitProviderConfigId gets a reference to the given string and assigns it to the GitProviderConfigId field. -func (o *CreateProjectConfigDTO) SetGitProviderConfigId(v string) { +func (o *CreateWorkspaceTemplateDTO) SetGitProviderConfigId(v string) { o.GitProviderConfigId = &v } // GetImage returns the Image field value if set, zero value otherwise. -func (o *CreateProjectConfigDTO) GetImage() string { +func (o *CreateWorkspaceTemplateDTO) GetImage() string { if o == nil || IsNil(o.Image) { var ret string return ret @@ -151,7 +151,7 @@ func (o *CreateProjectConfigDTO) GetImage() string { // GetImageOk returns a tuple with the Image field value if set, nil otherwise // and a boolean to check if the value has been set. -func (o *CreateProjectConfigDTO) GetImageOk() (*string, bool) { +func (o *CreateWorkspaceTemplateDTO) GetImageOk() (*string, bool) { if o == nil || IsNil(o.Image) { return nil, false } @@ -159,7 +159,7 @@ func (o *CreateProjectConfigDTO) GetImageOk() (*string, bool) { } // HasImage returns a boolean if a field has been set. -func (o *CreateProjectConfigDTO) HasImage() bool { +func (o *CreateWorkspaceTemplateDTO) HasImage() bool { if o != nil && !IsNil(o.Image) { return true } @@ -168,12 +168,12 @@ func (o *CreateProjectConfigDTO) HasImage() bool { } // SetImage gets a reference to the given string and assigns it to the Image field. -func (o *CreateProjectConfigDTO) SetImage(v string) { +func (o *CreateWorkspaceTemplateDTO) SetImage(v string) { o.Image = &v } // GetName returns the Name field value -func (o *CreateProjectConfigDTO) GetName() string { +func (o *CreateWorkspaceTemplateDTO) GetName() string { if o == nil { var ret string return ret @@ -184,7 +184,7 @@ func (o *CreateProjectConfigDTO) GetName() string { // GetNameOk returns a tuple with the Name field value // and a boolean to check if the value has been set. -func (o *CreateProjectConfigDTO) GetNameOk() (*string, bool) { +func (o *CreateWorkspaceTemplateDTO) GetNameOk() (*string, bool) { if o == nil { return nil, false } @@ -192,12 +192,12 @@ func (o *CreateProjectConfigDTO) GetNameOk() (*string, bool) { } // SetName sets field value -func (o *CreateProjectConfigDTO) SetName(v string) { +func (o *CreateWorkspaceTemplateDTO) SetName(v string) { o.Name = v } // GetRepositoryUrl returns the RepositoryUrl field value -func (o *CreateProjectConfigDTO) GetRepositoryUrl() string { +func (o *CreateWorkspaceTemplateDTO) GetRepositoryUrl() string { if o == nil { var ret string return ret @@ -208,7 +208,7 @@ func (o *CreateProjectConfigDTO) GetRepositoryUrl() string { // GetRepositoryUrlOk returns a tuple with the RepositoryUrl field value // and a boolean to check if the value has been set. -func (o *CreateProjectConfigDTO) GetRepositoryUrlOk() (*string, bool) { +func (o *CreateWorkspaceTemplateDTO) GetRepositoryUrlOk() (*string, bool) { if o == nil { return nil, false } @@ -216,12 +216,12 @@ func (o *CreateProjectConfigDTO) GetRepositoryUrlOk() (*string, bool) { } // SetRepositoryUrl sets field value -func (o *CreateProjectConfigDTO) SetRepositoryUrl(v string) { +func (o *CreateWorkspaceTemplateDTO) SetRepositoryUrl(v string) { o.RepositoryUrl = v } // GetUser returns the User field value if set, zero value otherwise. -func (o *CreateProjectConfigDTO) GetUser() string { +func (o *CreateWorkspaceTemplateDTO) GetUser() string { if o == nil || IsNil(o.User) { var ret string return ret @@ -231,7 +231,7 @@ func (o *CreateProjectConfigDTO) GetUser() string { // GetUserOk returns a tuple with the User field value if set, nil otherwise // and a boolean to check if the value has been set. -func (o *CreateProjectConfigDTO) GetUserOk() (*string, bool) { +func (o *CreateWorkspaceTemplateDTO) GetUserOk() (*string, bool) { if o == nil || IsNil(o.User) { return nil, false } @@ -239,7 +239,7 @@ func (o *CreateProjectConfigDTO) GetUserOk() (*string, bool) { } // HasUser returns a boolean if a field has been set. -func (o *CreateProjectConfigDTO) HasUser() bool { +func (o *CreateWorkspaceTemplateDTO) HasUser() bool { if o != nil && !IsNil(o.User) { return true } @@ -248,11 +248,11 @@ func (o *CreateProjectConfigDTO) HasUser() bool { } // SetUser gets a reference to the given string and assigns it to the User field. -func (o *CreateProjectConfigDTO) SetUser(v string) { +func (o *CreateWorkspaceTemplateDTO) SetUser(v string) { o.User = &v } -func (o CreateProjectConfigDTO) MarshalJSON() ([]byte, error) { +func (o CreateWorkspaceTemplateDTO) MarshalJSON() ([]byte, error) { toSerialize, err := o.ToMap() if err != nil { return []byte{}, err @@ -260,7 +260,7 @@ func (o CreateProjectConfigDTO) MarshalJSON() ([]byte, error) { return json.Marshal(toSerialize) } -func (o CreateProjectConfigDTO) ToMap() (map[string]interface{}, error) { +func (o CreateWorkspaceTemplateDTO) ToMap() (map[string]interface{}, error) { toSerialize := map[string]interface{}{} if !IsNil(o.BuildConfig) { toSerialize["buildConfig"] = o.BuildConfig @@ -280,7 +280,7 @@ func (o CreateProjectConfigDTO) ToMap() (map[string]interface{}, error) { return toSerialize, nil } -func (o *CreateProjectConfigDTO) UnmarshalJSON(data []byte) (err error) { +func (o *CreateWorkspaceTemplateDTO) UnmarshalJSON(data []byte) (err error) { // This validates that all required properties are included in the JSON object // by unmarshalling the object into a generic map with string keys and checking // that every required field exists as a key in the generic map. @@ -304,53 +304,53 @@ func (o *CreateProjectConfigDTO) UnmarshalJSON(data []byte) (err error) { } } - varCreateProjectConfigDTO := _CreateProjectConfigDTO{} + varCreateWorkspaceTemplateDTO := _CreateWorkspaceTemplateDTO{} decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() - err = decoder.Decode(&varCreateProjectConfigDTO) + err = decoder.Decode(&varCreateWorkspaceTemplateDTO) if err != nil { return err } - *o = CreateProjectConfigDTO(varCreateProjectConfigDTO) + *o = CreateWorkspaceTemplateDTO(varCreateWorkspaceTemplateDTO) return err } -type NullableCreateProjectConfigDTO struct { - value *CreateProjectConfigDTO +type NullableCreateWorkspaceTemplateDTO struct { + value *CreateWorkspaceTemplateDTO isSet bool } -func (v NullableCreateProjectConfigDTO) Get() *CreateProjectConfigDTO { +func (v NullableCreateWorkspaceTemplateDTO) Get() *CreateWorkspaceTemplateDTO { return v.value } -func (v *NullableCreateProjectConfigDTO) Set(val *CreateProjectConfigDTO) { +func (v *NullableCreateWorkspaceTemplateDTO) Set(val *CreateWorkspaceTemplateDTO) { v.value = val v.isSet = true } -func (v NullableCreateProjectConfigDTO) IsSet() bool { +func (v NullableCreateWorkspaceTemplateDTO) IsSet() bool { return v.isSet } -func (v *NullableCreateProjectConfigDTO) Unset() { +func (v *NullableCreateWorkspaceTemplateDTO) Unset() { v.value = nil v.isSet = false } -func NewNullableCreateProjectConfigDTO(val *CreateProjectConfigDTO) *NullableCreateProjectConfigDTO { - return &NullableCreateProjectConfigDTO{value: val, isSet: true} +func NewNullableCreateWorkspaceTemplateDTO(val *CreateWorkspaceTemplateDTO) *NullableCreateWorkspaceTemplateDTO { + return &NullableCreateWorkspaceTemplateDTO{value: val, isSet: true} } -func (v NullableCreateProjectConfigDTO) MarshalJSON() ([]byte, error) { +func (v NullableCreateWorkspaceTemplateDTO) MarshalJSON() ([]byte, error) { return json.Marshal(v.value) } -func (v *NullableCreateProjectConfigDTO) UnmarshalJSON(src []byte) error { +func (v *NullableCreateWorkspaceTemplateDTO) UnmarshalJSON(src []byte) error { v.isSet = true return json.Unmarshal(src, &v.value) } diff --git a/pkg/apiclient/model_environment_variable.go b/pkg/apiclient/model_environment_variable.go new file mode 100644 index 0000000000..305fed9e85 --- /dev/null +++ b/pkg/apiclient/model_environment_variable.go @@ -0,0 +1,184 @@ +/* +Daytona Server API + +Daytona Server API + +API version: v0.0.0-dev +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package apiclient + +import ( + "bytes" + "encoding/json" + "fmt" +) + +// checks if the EnvironmentVariable type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &EnvironmentVariable{} + +// EnvironmentVariable struct for EnvironmentVariable +type EnvironmentVariable struct { + Key string `json:"key"` + Value string `json:"value"` +} + +type _EnvironmentVariable EnvironmentVariable + +// NewEnvironmentVariable instantiates a new EnvironmentVariable object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewEnvironmentVariable(key string, value string) *EnvironmentVariable { + this := EnvironmentVariable{} + this.Key = key + this.Value = value + return &this +} + +// NewEnvironmentVariableWithDefaults instantiates a new EnvironmentVariable object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewEnvironmentVariableWithDefaults() *EnvironmentVariable { + this := EnvironmentVariable{} + return &this +} + +// GetKey returns the Key field value +func (o *EnvironmentVariable) GetKey() string { + if o == nil { + var ret string + return ret + } + + return o.Key +} + +// GetKeyOk returns a tuple with the Key field value +// and a boolean to check if the value has been set. +func (o *EnvironmentVariable) GetKeyOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Key, true +} + +// SetKey sets field value +func (o *EnvironmentVariable) SetKey(v string) { + o.Key = v +} + +// GetValue returns the Value field value +func (o *EnvironmentVariable) GetValue() string { + if o == nil { + var ret string + return ret + } + + return o.Value +} + +// GetValueOk returns a tuple with the Value field value +// and a boolean to check if the value has been set. +func (o *EnvironmentVariable) GetValueOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Value, true +} + +// SetValue sets field value +func (o *EnvironmentVariable) SetValue(v string) { + o.Value = v +} + +func (o EnvironmentVariable) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o EnvironmentVariable) ToMap() (map[string]interface{}, error) { + toSerialize := map[string]interface{}{} + toSerialize["key"] = o.Key + toSerialize["value"] = o.Value + return toSerialize, nil +} + +func (o *EnvironmentVariable) UnmarshalJSON(data []byte) (err error) { + // This validates that all required properties are included in the JSON object + // by unmarshalling the object into a generic map with string keys and checking + // that every required field exists as a key in the generic map. + requiredProperties := []string{ + "key", + "value", + } + + allProperties := make(map[string]interface{}) + + err = json.Unmarshal(data, &allProperties) + + if err != nil { + return err + } + + for _, requiredProperty := range requiredProperties { + if _, exists := allProperties[requiredProperty]; !exists { + return fmt.Errorf("no value given for required property %v", requiredProperty) + } + } + + varEnvironmentVariable := _EnvironmentVariable{} + + decoder := json.NewDecoder(bytes.NewReader(data)) + decoder.DisallowUnknownFields() + err = decoder.Decode(&varEnvironmentVariable) + + if err != nil { + return err + } + + *o = EnvironmentVariable(varEnvironmentVariable) + + return err +} + +type NullableEnvironmentVariable struct { + value *EnvironmentVariable + isSet bool +} + +func (v NullableEnvironmentVariable) Get() *EnvironmentVariable { + return v.value +} + +func (v *NullableEnvironmentVariable) Set(val *EnvironmentVariable) { + v.value = val + v.isSet = true +} + +func (v NullableEnvironmentVariable) IsSet() bool { + return v.isSet +} + +func (v *NullableEnvironmentVariable) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableEnvironmentVariable(val *EnvironmentVariable) *NullableEnvironmentVariable { + return &NullableEnvironmentVariable{value: val, isSet: true} +} + +func (v NullableEnvironmentVariable) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableEnvironmentVariable) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/pkg/apiclient/model_install_provider_request.go b/pkg/apiclient/model_install_provider_request.go deleted file mode 100644 index de1ab67098..0000000000 --- a/pkg/apiclient/model_install_provider_request.go +++ /dev/null @@ -1,184 +0,0 @@ -/* -Daytona Server API - -Daytona Server API - -API version: v0.0.0-dev -*/ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package apiclient - -import ( - "bytes" - "encoding/json" - "fmt" -) - -// checks if the InstallProviderRequest type satisfies the MappedNullable interface at compile time -var _ MappedNullable = &InstallProviderRequest{} - -// InstallProviderRequest struct for InstallProviderRequest -type InstallProviderRequest struct { - DownloadUrls map[string]string `json:"downloadUrls"` - Name string `json:"name"` -} - -type _InstallProviderRequest InstallProviderRequest - -// NewInstallProviderRequest instantiates a new InstallProviderRequest object -// This constructor will assign default values to properties that have it defined, -// and makes sure properties required by API are set, but the set of arguments -// will change when the set of required properties is changed -func NewInstallProviderRequest(downloadUrls map[string]string, name string) *InstallProviderRequest { - this := InstallProviderRequest{} - this.DownloadUrls = downloadUrls - this.Name = name - return &this -} - -// NewInstallProviderRequestWithDefaults instantiates a new InstallProviderRequest object -// This constructor will only assign default values to properties that have it defined, -// but it doesn't guarantee that properties required by API are set -func NewInstallProviderRequestWithDefaults() *InstallProviderRequest { - this := InstallProviderRequest{} - return &this -} - -// GetDownloadUrls returns the DownloadUrls field value -func (o *InstallProviderRequest) GetDownloadUrls() map[string]string { - if o == nil { - var ret map[string]string - return ret - } - - return o.DownloadUrls -} - -// GetDownloadUrlsOk returns a tuple with the DownloadUrls field value -// and a boolean to check if the value has been set. -func (o *InstallProviderRequest) GetDownloadUrlsOk() (*map[string]string, bool) { - if o == nil { - return nil, false - } - return &o.DownloadUrls, true -} - -// SetDownloadUrls sets field value -func (o *InstallProviderRequest) SetDownloadUrls(v map[string]string) { - o.DownloadUrls = v -} - -// GetName returns the Name field value -func (o *InstallProviderRequest) GetName() string { - if o == nil { - var ret string - return ret - } - - return o.Name -} - -// GetNameOk returns a tuple with the Name field value -// and a boolean to check if the value has been set. -func (o *InstallProviderRequest) GetNameOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.Name, true -} - -// SetName sets field value -func (o *InstallProviderRequest) SetName(v string) { - o.Name = v -} - -func (o InstallProviderRequest) MarshalJSON() ([]byte, error) { - toSerialize, err := o.ToMap() - if err != nil { - return []byte{}, err - } - return json.Marshal(toSerialize) -} - -func (o InstallProviderRequest) ToMap() (map[string]interface{}, error) { - toSerialize := map[string]interface{}{} - toSerialize["downloadUrls"] = o.DownloadUrls - toSerialize["name"] = o.Name - return toSerialize, nil -} - -func (o *InstallProviderRequest) UnmarshalJSON(data []byte) (err error) { - // This validates that all required properties are included in the JSON object - // by unmarshalling the object into a generic map with string keys and checking - // that every required field exists as a key in the generic map. - requiredProperties := []string{ - "downloadUrls", - "name", - } - - allProperties := make(map[string]interface{}) - - err = json.Unmarshal(data, &allProperties) - - if err != nil { - return err - } - - for _, requiredProperty := range requiredProperties { - if _, exists := allProperties[requiredProperty]; !exists { - return fmt.Errorf("no value given for required property %v", requiredProperty) - } - } - - varInstallProviderRequest := _InstallProviderRequest{} - - decoder := json.NewDecoder(bytes.NewReader(data)) - decoder.DisallowUnknownFields() - err = decoder.Decode(&varInstallProviderRequest) - - if err != nil { - return err - } - - *o = InstallProviderRequest(varInstallProviderRequest) - - return err -} - -type NullableInstallProviderRequest struct { - value *InstallProviderRequest - isSet bool -} - -func (v NullableInstallProviderRequest) Get() *InstallProviderRequest { - return v.value -} - -func (v *NullableInstallProviderRequest) Set(val *InstallProviderRequest) { - v.value = val - v.isSet = true -} - -func (v NullableInstallProviderRequest) IsSet() bool { - return v.isSet -} - -func (v *NullableInstallProviderRequest) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableInstallProviderRequest(val *InstallProviderRequest) *NullableInstallProviderRequest { - return &NullableInstallProviderRequest{value: val, isSet: true} -} - -func (v NullableInstallProviderRequest) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableInstallProviderRequest) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/pkg/apiclient/model_job.go b/pkg/apiclient/model_job.go new file mode 100644 index 0000000000..6561bc1a92 --- /dev/null +++ b/pkg/apiclient/model_job.go @@ -0,0 +1,433 @@ +/* +Daytona Server API + +Daytona Server API + +API version: v0.0.0-dev +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package apiclient + +import ( + "bytes" + "encoding/json" + "fmt" +) + +// checks if the Job type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &Job{} + +// Job struct for Job +type Job struct { + Action ModelsJobAction `json:"action"` + CreatedAt string `json:"createdAt"` + Error *string `json:"error,omitempty"` + Id string `json:"id"` + // JSON encoded metadata + Metadata *string `json:"metadata,omitempty"` + ResourceId string `json:"resourceId"` + ResourceType ResourceType `json:"resourceType"` + RunnerId *string `json:"runnerId,omitempty"` + State JobState `json:"state"` + UpdatedAt string `json:"updatedAt"` +} + +type _Job Job + +// NewJob instantiates a new Job object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewJob(action ModelsJobAction, createdAt string, id string, resourceId string, resourceType ResourceType, state JobState, updatedAt string) *Job { + this := Job{} + this.Action = action + this.CreatedAt = createdAt + this.Id = id + this.ResourceId = resourceId + this.ResourceType = resourceType + this.State = state + this.UpdatedAt = updatedAt + return &this +} + +// NewJobWithDefaults instantiates a new Job object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewJobWithDefaults() *Job { + this := Job{} + return &this +} + +// GetAction returns the Action field value +func (o *Job) GetAction() ModelsJobAction { + if o == nil { + var ret ModelsJobAction + return ret + } + + return o.Action +} + +// GetActionOk returns a tuple with the Action field value +// and a boolean to check if the value has been set. +func (o *Job) GetActionOk() (*ModelsJobAction, bool) { + if o == nil { + return nil, false + } + return &o.Action, true +} + +// SetAction sets field value +func (o *Job) SetAction(v ModelsJobAction) { + o.Action = v +} + +// GetCreatedAt returns the CreatedAt field value +func (o *Job) GetCreatedAt() string { + if o == nil { + var ret string + return ret + } + + return o.CreatedAt +} + +// GetCreatedAtOk returns a tuple with the CreatedAt field value +// and a boolean to check if the value has been set. +func (o *Job) GetCreatedAtOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.CreatedAt, true +} + +// SetCreatedAt sets field value +func (o *Job) SetCreatedAt(v string) { + o.CreatedAt = v +} + +// GetError returns the Error field value if set, zero value otherwise. +func (o *Job) GetError() string { + if o == nil || IsNil(o.Error) { + var ret string + return ret + } + return *o.Error +} + +// GetErrorOk returns a tuple with the Error field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *Job) GetErrorOk() (*string, bool) { + if o == nil || IsNil(o.Error) { + return nil, false + } + return o.Error, true +} + +// HasError returns a boolean if a field has been set. +func (o *Job) HasError() bool { + if o != nil && !IsNil(o.Error) { + return true + } + + return false +} + +// SetError gets a reference to the given string and assigns it to the Error field. +func (o *Job) SetError(v string) { + o.Error = &v +} + +// GetId returns the Id field value +func (o *Job) GetId() string { + if o == nil { + var ret string + return ret + } + + return o.Id +} + +// GetIdOk returns a tuple with the Id field value +// and a boolean to check if the value has been set. +func (o *Job) GetIdOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Id, true +} + +// SetId sets field value +func (o *Job) SetId(v string) { + o.Id = v +} + +// GetMetadata returns the Metadata field value if set, zero value otherwise. +func (o *Job) GetMetadata() string { + if o == nil || IsNil(o.Metadata) { + var ret string + return ret + } + return *o.Metadata +} + +// GetMetadataOk returns a tuple with the Metadata field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *Job) GetMetadataOk() (*string, bool) { + if o == nil || IsNil(o.Metadata) { + return nil, false + } + return o.Metadata, true +} + +// HasMetadata returns a boolean if a field has been set. +func (o *Job) HasMetadata() bool { + if o != nil && !IsNil(o.Metadata) { + return true + } + + return false +} + +// SetMetadata gets a reference to the given string and assigns it to the Metadata field. +func (o *Job) SetMetadata(v string) { + o.Metadata = &v +} + +// GetResourceId returns the ResourceId field value +func (o *Job) GetResourceId() string { + if o == nil { + var ret string + return ret + } + + return o.ResourceId +} + +// GetResourceIdOk returns a tuple with the ResourceId field value +// and a boolean to check if the value has been set. +func (o *Job) GetResourceIdOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.ResourceId, true +} + +// SetResourceId sets field value +func (o *Job) SetResourceId(v string) { + o.ResourceId = v +} + +// GetResourceType returns the ResourceType field value +func (o *Job) GetResourceType() ResourceType { + if o == nil { + var ret ResourceType + return ret + } + + return o.ResourceType +} + +// GetResourceTypeOk returns a tuple with the ResourceType field value +// and a boolean to check if the value has been set. +func (o *Job) GetResourceTypeOk() (*ResourceType, bool) { + if o == nil { + return nil, false + } + return &o.ResourceType, true +} + +// SetResourceType sets field value +func (o *Job) SetResourceType(v ResourceType) { + o.ResourceType = v +} + +// GetRunnerId returns the RunnerId field value if set, zero value otherwise. +func (o *Job) GetRunnerId() string { + if o == nil || IsNil(o.RunnerId) { + var ret string + return ret + } + return *o.RunnerId +} + +// GetRunnerIdOk returns a tuple with the RunnerId field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *Job) GetRunnerIdOk() (*string, bool) { + if o == nil || IsNil(o.RunnerId) { + return nil, false + } + return o.RunnerId, true +} + +// HasRunnerId returns a boolean if a field has been set. +func (o *Job) HasRunnerId() bool { + if o != nil && !IsNil(o.RunnerId) { + return true + } + + return false +} + +// SetRunnerId gets a reference to the given string and assigns it to the RunnerId field. +func (o *Job) SetRunnerId(v string) { + o.RunnerId = &v +} + +// GetState returns the State field value +func (o *Job) GetState() JobState { + if o == nil { + var ret JobState + return ret + } + + return o.State +} + +// GetStateOk returns a tuple with the State field value +// and a boolean to check if the value has been set. +func (o *Job) GetStateOk() (*JobState, bool) { + if o == nil { + return nil, false + } + return &o.State, true +} + +// SetState sets field value +func (o *Job) SetState(v JobState) { + o.State = v +} + +// GetUpdatedAt returns the UpdatedAt field value +func (o *Job) GetUpdatedAt() string { + if o == nil { + var ret string + return ret + } + + return o.UpdatedAt +} + +// GetUpdatedAtOk returns a tuple with the UpdatedAt field value +// and a boolean to check if the value has been set. +func (o *Job) GetUpdatedAtOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.UpdatedAt, true +} + +// SetUpdatedAt sets field value +func (o *Job) SetUpdatedAt(v string) { + o.UpdatedAt = v +} + +func (o Job) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o Job) ToMap() (map[string]interface{}, error) { + toSerialize := map[string]interface{}{} + toSerialize["action"] = o.Action + toSerialize["createdAt"] = o.CreatedAt + if !IsNil(o.Error) { + toSerialize["error"] = o.Error + } + toSerialize["id"] = o.Id + if !IsNil(o.Metadata) { + toSerialize["metadata"] = o.Metadata + } + toSerialize["resourceId"] = o.ResourceId + toSerialize["resourceType"] = o.ResourceType + if !IsNil(o.RunnerId) { + toSerialize["runnerId"] = o.RunnerId + } + toSerialize["state"] = o.State + toSerialize["updatedAt"] = o.UpdatedAt + return toSerialize, nil +} + +func (o *Job) UnmarshalJSON(data []byte) (err error) { + // This validates that all required properties are included in the JSON object + // by unmarshalling the object into a generic map with string keys and checking + // that every required field exists as a key in the generic map. + requiredProperties := []string{ + "action", + "createdAt", + "id", + "resourceId", + "resourceType", + "state", + "updatedAt", + } + + allProperties := make(map[string]interface{}) + + err = json.Unmarshal(data, &allProperties) + + if err != nil { + return err + } + + for _, requiredProperty := range requiredProperties { + if _, exists := allProperties[requiredProperty]; !exists { + return fmt.Errorf("no value given for required property %v", requiredProperty) + } + } + + varJob := _Job{} + + decoder := json.NewDecoder(bytes.NewReader(data)) + decoder.DisallowUnknownFields() + err = decoder.Decode(&varJob) + + if err != nil { + return err + } + + *o = Job(varJob) + + return err +} + +type NullableJob struct { + value *Job + isSet bool +} + +func (v NullableJob) Get() *Job { + return v.value +} + +func (v *NullableJob) Set(val *Job) { + v.value = val + v.isSet = true +} + +func (v NullableJob) IsSet() bool { + return v.isSet +} + +func (v *NullableJob) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableJob(val *Job) *NullableJob { + return &NullableJob{value: val, isSet: true} +} + +func (v NullableJob) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableJob) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/pkg/apiclient/model_job_state.go b/pkg/apiclient/model_job_state.go new file mode 100644 index 0000000000..198b95eb9f --- /dev/null +++ b/pkg/apiclient/model_job_state.go @@ -0,0 +1,114 @@ +/* +Daytona Server API + +Daytona Server API + +API version: v0.0.0-dev +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package apiclient + +import ( + "encoding/json" + "fmt" +) + +// JobState the model 'JobState' +type JobState string + +// List of JobState +const ( + JobStatePending JobState = "pending" + JobStateRunning JobState = "running" + JobStateError JobState = "error" + JobStateSuccess JobState = "success" +) + +// All allowed values of JobState enum +var AllowedJobStateEnumValues = []JobState{ + "pending", + "running", + "error", + "success", +} + +func (v *JobState) UnmarshalJSON(src []byte) error { + var value string + err := json.Unmarshal(src, &value) + if err != nil { + return err + } + enumTypeValue := JobState(value) + for _, existing := range AllowedJobStateEnumValues { + if existing == enumTypeValue { + *v = enumTypeValue + return nil + } + } + + return fmt.Errorf("%+v is not a valid JobState", value) +} + +// NewJobStateFromValue returns a pointer to a valid JobState +// for the value passed as argument, or an error if the value passed is not allowed by the enum +func NewJobStateFromValue(v string) (*JobState, error) { + ev := JobState(v) + if ev.IsValid() { + return &ev, nil + } else { + return nil, fmt.Errorf("invalid value '%v' for JobState: valid values are %v", v, AllowedJobStateEnumValues) + } +} + +// IsValid return true if the value is valid for the enum, false otherwise +func (v JobState) IsValid() bool { + for _, existing := range AllowedJobStateEnumValues { + if existing == v { + return true + } + } + return false +} + +// Ptr returns reference to JobState value +func (v JobState) Ptr() *JobState { + return &v +} + +type NullableJobState struct { + value *JobState + isSet bool +} + +func (v NullableJobState) Get() *JobState { + return v.value +} + +func (v *NullableJobState) Set(val *JobState) { + v.value = val + v.isSet = true +} + +func (v NullableJobState) IsSet() bool { + return v.isSet +} + +func (v *NullableJobState) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableJobState(val *JobState) *NullableJobState { + return &NullableJobState{value: val, isSet: true} +} + +func (v NullableJobState) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableJobState) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/pkg/apiclient/model_models_api_key_type.go b/pkg/apiclient/model_models_api_key_type.go new file mode 100644 index 0000000000..b202669443 --- /dev/null +++ b/pkg/apiclient/model_models_api_key_type.go @@ -0,0 +1,114 @@ +/* +Daytona Server API + +Daytona Server API + +API version: v0.0.0-dev +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package apiclient + +import ( + "encoding/json" + "fmt" +) + +// ModelsApiKeyType the model 'ModelsApiKeyType' +type ModelsApiKeyType string + +// List of models.ApiKeyType +const ( + ApiKeyTypeClient ModelsApiKeyType = "client" + ApiKeyTypeWorkspace ModelsApiKeyType = "workspace" + ApiKeyTypeTarget ModelsApiKeyType = "target" + ApiKeyTypeRunner ModelsApiKeyType = "runner" +) + +// All allowed values of ModelsApiKeyType enum +var AllowedModelsApiKeyTypeEnumValues = []ModelsApiKeyType{ + "client", + "workspace", + "target", + "runner", +} + +func (v *ModelsApiKeyType) UnmarshalJSON(src []byte) error { + var value string + err := json.Unmarshal(src, &value) + if err != nil { + return err + } + enumTypeValue := ModelsApiKeyType(value) + for _, existing := range AllowedModelsApiKeyTypeEnumValues { + if existing == enumTypeValue { + *v = enumTypeValue + return nil + } + } + + return fmt.Errorf("%+v is not a valid ModelsApiKeyType", value) +} + +// NewModelsApiKeyTypeFromValue returns a pointer to a valid ModelsApiKeyType +// for the value passed as argument, or an error if the value passed is not allowed by the enum +func NewModelsApiKeyTypeFromValue(v string) (*ModelsApiKeyType, error) { + ev := ModelsApiKeyType(v) + if ev.IsValid() { + return &ev, nil + } else { + return nil, fmt.Errorf("invalid value '%v' for ModelsApiKeyType: valid values are %v", v, AllowedModelsApiKeyTypeEnumValues) + } +} + +// IsValid return true if the value is valid for the enum, false otherwise +func (v ModelsApiKeyType) IsValid() bool { + for _, existing := range AllowedModelsApiKeyTypeEnumValues { + if existing == v { + return true + } + } + return false +} + +// Ptr returns reference to models.ApiKeyType value +func (v ModelsApiKeyType) Ptr() *ModelsApiKeyType { + return &v +} + +type NullableModelsApiKeyType struct { + value *ModelsApiKeyType + isSet bool +} + +func (v NullableModelsApiKeyType) Get() *ModelsApiKeyType { + return v.value +} + +func (v *NullableModelsApiKeyType) Set(val *ModelsApiKeyType) { + v.value = val + v.isSet = true +} + +func (v NullableModelsApiKeyType) IsSet() bool { + return v.isSet +} + +func (v *NullableModelsApiKeyType) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableModelsApiKeyType(val *ModelsApiKeyType) *NullableModelsApiKeyType { + return &NullableModelsApiKeyType{value: val, isSet: true} +} + +func (v NullableModelsApiKeyType) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableModelsApiKeyType) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/pkg/apiclient/model_models_job_action.go b/pkg/apiclient/model_models_job_action.go new file mode 100644 index 0000000000..5463e65323 --- /dev/null +++ b/pkg/apiclient/model_models_job_action.go @@ -0,0 +1,126 @@ +/* +Daytona Server API + +Daytona Server API + +API version: v0.0.0-dev +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package apiclient + +import ( + "encoding/json" + "fmt" +) + +// ModelsJobAction the model 'ModelsJobAction' +type ModelsJobAction string + +// List of models.JobAction +const ( + JobActionCreate ModelsJobAction = "create" + JobActionStart ModelsJobAction = "start" + JobActionStop ModelsJobAction = "stop" + JobActionRestart ModelsJobAction = "restart" + JobActionDelete ModelsJobAction = "delete" + JobActionForceDelete ModelsJobAction = "force-delete" + JobActionRun ModelsJobAction = "run" + JobActionInstallProvider ModelsJobAction = "install-provider" + JobActionUninstallProvider ModelsJobAction = "uninstall-provider" + JobActionUpdateProvider ModelsJobAction = "update-provider" +) + +// All allowed values of ModelsJobAction enum +var AllowedModelsJobActionEnumValues = []ModelsJobAction{ + "create", + "start", + "stop", + "restart", + "delete", + "force-delete", + "run", + "install-provider", + "uninstall-provider", + "update-provider", +} + +func (v *ModelsJobAction) UnmarshalJSON(src []byte) error { + var value string + err := json.Unmarshal(src, &value) + if err != nil { + return err + } + enumTypeValue := ModelsJobAction(value) + for _, existing := range AllowedModelsJobActionEnumValues { + if existing == enumTypeValue { + *v = enumTypeValue + return nil + } + } + + return fmt.Errorf("%+v is not a valid ModelsJobAction", value) +} + +// NewModelsJobActionFromValue returns a pointer to a valid ModelsJobAction +// for the value passed as argument, or an error if the value passed is not allowed by the enum +func NewModelsJobActionFromValue(v string) (*ModelsJobAction, error) { + ev := ModelsJobAction(v) + if ev.IsValid() { + return &ev, nil + } else { + return nil, fmt.Errorf("invalid value '%v' for ModelsJobAction: valid values are %v", v, AllowedModelsJobActionEnumValues) + } +} + +// IsValid return true if the value is valid for the enum, false otherwise +func (v ModelsJobAction) IsValid() bool { + for _, existing := range AllowedModelsJobActionEnumValues { + if existing == v { + return true + } + } + return false +} + +// Ptr returns reference to models.JobAction value +func (v ModelsJobAction) Ptr() *ModelsJobAction { + return &v +} + +type NullableModelsJobAction struct { + value *ModelsJobAction + isSet bool +} + +func (v NullableModelsJobAction) Get() *ModelsJobAction { + return v.value +} + +func (v *NullableModelsJobAction) Set(val *ModelsJobAction) { + v.value = val + v.isSet = true +} + +func (v NullableModelsJobAction) IsSet() bool { + return v.isSet +} + +func (v *NullableModelsJobAction) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableModelsJobAction(val *ModelsJobAction) *NullableModelsJobAction { + return &NullableModelsJobAction{value: val, isSet: true} +} + +func (v NullableModelsJobAction) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableModelsJobAction) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/pkg/apiclient/model_models_resource_state_name.go b/pkg/apiclient/model_models_resource_state_name.go new file mode 100644 index 0000000000..ffaba87386 --- /dev/null +++ b/pkg/apiclient/model_models_resource_state_name.go @@ -0,0 +1,144 @@ +/* +Daytona Server API + +Daytona Server API + +API version: v0.0.0-dev +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package apiclient + +import ( + "encoding/json" + "fmt" +) + +// ModelsResourceStateName the model 'ModelsResourceStateName' +type ModelsResourceStateName string + +// List of models.ResourceStateName +const ( + ResourceStateNameUndefined ModelsResourceStateName = "undefined" + ResourceStateNamePendingRun ModelsResourceStateName = "pending-run" + ResourceStateNameRunning ModelsResourceStateName = "running" + ResourceStateNameRunSuccessful ModelsResourceStateName = "run-successful" + ResourceStateNamePendingCreate ModelsResourceStateName = "pending-create" + ResourceStateNameCreating ModelsResourceStateName = "creating" + ResourceStateNamePendingStart ModelsResourceStateName = "pending-start" + ResourceStateNameStarting ModelsResourceStateName = "starting" + ResourceStateNameStarted ModelsResourceStateName = "started" + ResourceStateNamePendingStop ModelsResourceStateName = "pending-stop" + ResourceStateNameStopping ModelsResourceStateName = "stopping" + ResourceStateNameStopped ModelsResourceStateName = "stopped" + ResourceStateNamePendingRestart ModelsResourceStateName = "pending-restart" + ResourceStateNameError ModelsResourceStateName = "error" + ResourceStateNameUnresponsive ModelsResourceStateName = "unresponsive" + ResourceStateNamePendingDelete ModelsResourceStateName = "pending-delete" + ResourceStateNamePendingForcedDelete ModelsResourceStateName = "pending-forced-delete" + ResourceStateNameDeleting ModelsResourceStateName = "deleting" + ResourceStateNameDeleted ModelsResourceStateName = "deleted" +) + +// All allowed values of ModelsResourceStateName enum +var AllowedModelsResourceStateNameEnumValues = []ModelsResourceStateName{ + "undefined", + "pending-run", + "running", + "run-successful", + "pending-create", + "creating", + "pending-start", + "starting", + "started", + "pending-stop", + "stopping", + "stopped", + "pending-restart", + "error", + "unresponsive", + "pending-delete", + "pending-forced-delete", + "deleting", + "deleted", +} + +func (v *ModelsResourceStateName) UnmarshalJSON(src []byte) error { + var value string + err := json.Unmarshal(src, &value) + if err != nil { + return err + } + enumTypeValue := ModelsResourceStateName(value) + for _, existing := range AllowedModelsResourceStateNameEnumValues { + if existing == enumTypeValue { + *v = enumTypeValue + return nil + } + } + + return fmt.Errorf("%+v is not a valid ModelsResourceStateName", value) +} + +// NewModelsResourceStateNameFromValue returns a pointer to a valid ModelsResourceStateName +// for the value passed as argument, or an error if the value passed is not allowed by the enum +func NewModelsResourceStateNameFromValue(v string) (*ModelsResourceStateName, error) { + ev := ModelsResourceStateName(v) + if ev.IsValid() { + return &ev, nil + } else { + return nil, fmt.Errorf("invalid value '%v' for ModelsResourceStateName: valid values are %v", v, AllowedModelsResourceStateNameEnumValues) + } +} + +// IsValid return true if the value is valid for the enum, false otherwise +func (v ModelsResourceStateName) IsValid() bool { + for _, existing := range AllowedModelsResourceStateNameEnumValues { + if existing == v { + return true + } + } + return false +} + +// Ptr returns reference to models.ResourceStateName value +func (v ModelsResourceStateName) Ptr() *ModelsResourceStateName { + return &v +} + +type NullableModelsResourceStateName struct { + value *ModelsResourceStateName + isSet bool +} + +func (v NullableModelsResourceStateName) Get() *ModelsResourceStateName { + return v.value +} + +func (v *NullableModelsResourceStateName) Set(val *ModelsResourceStateName) { + v.value = val + v.isSet = true +} + +func (v NullableModelsResourceStateName) IsSet() bool { + return v.isSet +} + +func (v *NullableModelsResourceStateName) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableModelsResourceStateName(val *ModelsResourceStateName) *NullableModelsResourceStateName { + return &NullableModelsResourceStateName{value: val, isSet: true} +} + +func (v NullableModelsResourceStateName) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableModelsResourceStateName) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/pkg/apiclient/model_models_target_config_property_type.go b/pkg/apiclient/model_models_target_config_property_type.go new file mode 100644 index 0000000000..bd675825c1 --- /dev/null +++ b/pkg/apiclient/model_models_target_config_property_type.go @@ -0,0 +1,118 @@ +/* +Daytona Server API + +Daytona Server API + +API version: v0.0.0-dev +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package apiclient + +import ( + "encoding/json" + "fmt" +) + +// ModelsTargetConfigPropertyType the model 'ModelsTargetConfigPropertyType' +type ModelsTargetConfigPropertyType string + +// List of models.TargetConfigPropertyType +const ( + TargetConfigPropertyTypeString ModelsTargetConfigPropertyType = "string" + TargetConfigPropertyTypeOption ModelsTargetConfigPropertyType = "option" + TargetConfigPropertyTypeBoolean ModelsTargetConfigPropertyType = "boolean" + TargetConfigPropertyTypeInt ModelsTargetConfigPropertyType = "int" + TargetConfigPropertyTypeFloat ModelsTargetConfigPropertyType = "float" + TargetConfigPropertyTypeFilePath ModelsTargetConfigPropertyType = "file-path" +) + +// All allowed values of ModelsTargetConfigPropertyType enum +var AllowedModelsTargetConfigPropertyTypeEnumValues = []ModelsTargetConfigPropertyType{ + "string", + "option", + "boolean", + "int", + "float", + "file-path", +} + +func (v *ModelsTargetConfigPropertyType) UnmarshalJSON(src []byte) error { + var value string + err := json.Unmarshal(src, &value) + if err != nil { + return err + } + enumTypeValue := ModelsTargetConfigPropertyType(value) + for _, existing := range AllowedModelsTargetConfigPropertyTypeEnumValues { + if existing == enumTypeValue { + *v = enumTypeValue + return nil + } + } + + return fmt.Errorf("%+v is not a valid ModelsTargetConfigPropertyType", value) +} + +// NewModelsTargetConfigPropertyTypeFromValue returns a pointer to a valid ModelsTargetConfigPropertyType +// for the value passed as argument, or an error if the value passed is not allowed by the enum +func NewModelsTargetConfigPropertyTypeFromValue(v string) (*ModelsTargetConfigPropertyType, error) { + ev := ModelsTargetConfigPropertyType(v) + if ev.IsValid() { + return &ev, nil + } else { + return nil, fmt.Errorf("invalid value '%v' for ModelsTargetConfigPropertyType: valid values are %v", v, AllowedModelsTargetConfigPropertyTypeEnumValues) + } +} + +// IsValid return true if the value is valid for the enum, false otherwise +func (v ModelsTargetConfigPropertyType) IsValid() bool { + for _, existing := range AllowedModelsTargetConfigPropertyTypeEnumValues { + if existing == v { + return true + } + } + return false +} + +// Ptr returns reference to models.TargetConfigPropertyType value +func (v ModelsTargetConfigPropertyType) Ptr() *ModelsTargetConfigPropertyType { + return &v +} + +type NullableModelsTargetConfigPropertyType struct { + value *ModelsTargetConfigPropertyType + isSet bool +} + +func (v NullableModelsTargetConfigPropertyType) Get() *ModelsTargetConfigPropertyType { + return v.value +} + +func (v *NullableModelsTargetConfigPropertyType) Set(val *ModelsTargetConfigPropertyType) { + v.value = val + v.isSet = true +} + +func (v NullableModelsTargetConfigPropertyType) IsSet() bool { + return v.isSet +} + +func (v *NullableModelsTargetConfigPropertyType) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableModelsTargetConfigPropertyType(val *ModelsTargetConfigPropertyType) *NullableModelsTargetConfigPropertyType { + return &NullableModelsTargetConfigPropertyType{value: val, isSet: true} +} + +func (v NullableModelsTargetConfigPropertyType) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableModelsTargetConfigPropertyType) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/pkg/apiclient/model_prebuild_config.go b/pkg/apiclient/model_prebuild_config.go index b018c656bc..b4e3086eed 100644 --- a/pkg/apiclient/model_prebuild_config.go +++ b/pkg/apiclient/model_prebuild_config.go @@ -22,7 +22,7 @@ var _ MappedNullable = &PrebuildConfig{} // PrebuildConfig struct for PrebuildConfig type PrebuildConfig struct { Branch string `json:"branch"` - CommitInterval int32 `json:"commitInterval"` + CommitInterval *int32 `json:"commitInterval,omitempty"` Id string `json:"id"` Retention int32 `json:"retention"` TriggerFiles []string `json:"triggerFiles"` @@ -34,10 +34,9 @@ type _PrebuildConfig PrebuildConfig // This constructor will assign default values to properties that have it defined, // and makes sure properties required by API are set, but the set of arguments // will change when the set of required properties is changed -func NewPrebuildConfig(branch string, commitInterval int32, id string, retention int32, triggerFiles []string) *PrebuildConfig { +func NewPrebuildConfig(branch string, id string, retention int32, triggerFiles []string) *PrebuildConfig { this := PrebuildConfig{} this.Branch = branch - this.CommitInterval = commitInterval this.Id = id this.Retention = retention this.TriggerFiles = triggerFiles @@ -76,28 +75,36 @@ func (o *PrebuildConfig) SetBranch(v string) { o.Branch = v } -// GetCommitInterval returns the CommitInterval field value +// GetCommitInterval returns the CommitInterval field value if set, zero value otherwise. func (o *PrebuildConfig) GetCommitInterval() int32 { - if o == nil { + if o == nil || IsNil(o.CommitInterval) { var ret int32 return ret } - - return o.CommitInterval + return *o.CommitInterval } -// GetCommitIntervalOk returns a tuple with the CommitInterval field value +// GetCommitIntervalOk returns a tuple with the CommitInterval field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *PrebuildConfig) GetCommitIntervalOk() (*int32, bool) { - if o == nil { + if o == nil || IsNil(o.CommitInterval) { return nil, false } - return &o.CommitInterval, true + return o.CommitInterval, true +} + +// HasCommitInterval returns a boolean if a field has been set. +func (o *PrebuildConfig) HasCommitInterval() bool { + if o != nil && !IsNil(o.CommitInterval) { + return true + } + + return false } -// SetCommitInterval sets field value +// SetCommitInterval gets a reference to the given int32 and assigns it to the CommitInterval field. func (o *PrebuildConfig) SetCommitInterval(v int32) { - o.CommitInterval = v + o.CommitInterval = &v } // GetId returns the Id field value @@ -183,7 +190,9 @@ func (o PrebuildConfig) MarshalJSON() ([]byte, error) { func (o PrebuildConfig) ToMap() (map[string]interface{}, error) { toSerialize := map[string]interface{}{} toSerialize["branch"] = o.Branch - toSerialize["commitInterval"] = o.CommitInterval + if !IsNil(o.CommitInterval) { + toSerialize["commitInterval"] = o.CommitInterval + } toSerialize["id"] = o.Id toSerialize["retention"] = o.Retention toSerialize["triggerFiles"] = o.TriggerFiles @@ -196,7 +205,6 @@ func (o *PrebuildConfig) UnmarshalJSON(data []byte) (err error) { // that every required field exists as a key in the generic map. requiredProperties := []string{ "branch", - "commitInterval", "id", "retention", "triggerFiles", diff --git a/pkg/apiclient/model_prebuild_dto.go b/pkg/apiclient/model_prebuild_dto.go index 644591858c..8cf33c5c3b 100644 --- a/pkg/apiclient/model_prebuild_dto.go +++ b/pkg/apiclient/model_prebuild_dto.go @@ -21,12 +21,12 @@ var _ MappedNullable = &PrebuildDTO{} // PrebuildDTO struct for PrebuildDTO type PrebuildDTO struct { - Branch string `json:"branch"` - CommitInterval *int32 `json:"commitInterval,omitempty"` - Id string `json:"id"` - ProjectConfigName string `json:"projectConfigName"` - Retention int32 `json:"retention"` - TriggerFiles []string `json:"triggerFiles,omitempty"` + Branch string `json:"branch"` + CommitInterval *int32 `json:"commitInterval,omitempty"` + Id string `json:"id"` + Retention int32 `json:"retention"` + TriggerFiles []string `json:"triggerFiles,omitempty"` + WorkspaceTemplateName string `json:"workspaceTemplateName"` } type _PrebuildDTO PrebuildDTO @@ -35,12 +35,12 @@ type _PrebuildDTO PrebuildDTO // This constructor will assign default values to properties that have it defined, // and makes sure properties required by API are set, but the set of arguments // will change when the set of required properties is changed -func NewPrebuildDTO(branch string, id string, projectConfigName string, retention int32) *PrebuildDTO { +func NewPrebuildDTO(branch string, id string, retention int32, workspaceTemplateName string) *PrebuildDTO { this := PrebuildDTO{} this.Branch = branch this.Id = id - this.ProjectConfigName = projectConfigName this.Retention = retention + this.WorkspaceTemplateName = workspaceTemplateName return &this } @@ -132,30 +132,6 @@ func (o *PrebuildDTO) SetId(v string) { o.Id = v } -// GetProjectConfigName returns the ProjectConfigName field value -func (o *PrebuildDTO) GetProjectConfigName() string { - if o == nil { - var ret string - return ret - } - - return o.ProjectConfigName -} - -// GetProjectConfigNameOk returns a tuple with the ProjectConfigName field value -// and a boolean to check if the value has been set. -func (o *PrebuildDTO) GetProjectConfigNameOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.ProjectConfigName, true -} - -// SetProjectConfigName sets field value -func (o *PrebuildDTO) SetProjectConfigName(v string) { - o.ProjectConfigName = v -} - // GetRetention returns the Retention field value func (o *PrebuildDTO) GetRetention() int32 { if o == nil { @@ -212,6 +188,30 @@ func (o *PrebuildDTO) SetTriggerFiles(v []string) { o.TriggerFiles = v } +// GetWorkspaceTemplateName returns the WorkspaceTemplateName field value +func (o *PrebuildDTO) GetWorkspaceTemplateName() string { + if o == nil { + var ret string + return ret + } + + return o.WorkspaceTemplateName +} + +// GetWorkspaceTemplateNameOk returns a tuple with the WorkspaceTemplateName field value +// and a boolean to check if the value has been set. +func (o *PrebuildDTO) GetWorkspaceTemplateNameOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.WorkspaceTemplateName, true +} + +// SetWorkspaceTemplateName sets field value +func (o *PrebuildDTO) SetWorkspaceTemplateName(v string) { + o.WorkspaceTemplateName = v +} + func (o PrebuildDTO) MarshalJSON() ([]byte, error) { toSerialize, err := o.ToMap() if err != nil { @@ -227,11 +227,11 @@ func (o PrebuildDTO) ToMap() (map[string]interface{}, error) { toSerialize["commitInterval"] = o.CommitInterval } toSerialize["id"] = o.Id - toSerialize["projectConfigName"] = o.ProjectConfigName toSerialize["retention"] = o.Retention if !IsNil(o.TriggerFiles) { toSerialize["triggerFiles"] = o.TriggerFiles } + toSerialize["workspaceTemplateName"] = o.WorkspaceTemplateName return toSerialize, nil } @@ -242,8 +242,8 @@ func (o *PrebuildDTO) UnmarshalJSON(data []byte) (err error) { requiredProperties := []string{ "branch", "id", - "projectConfigName", "retention", + "workspaceTemplateName", } allProperties := make(map[string]interface{}) diff --git a/pkg/apiclient/model_profile_data.go b/pkg/apiclient/model_profile_data.go deleted file mode 100644 index d7eabbe8f4..0000000000 --- a/pkg/apiclient/model_profile_data.go +++ /dev/null @@ -1,156 +0,0 @@ -/* -Daytona Server API - -Daytona Server API - -API version: v0.0.0-dev -*/ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package apiclient - -import ( - "bytes" - "encoding/json" - "fmt" -) - -// checks if the ProfileData type satisfies the MappedNullable interface at compile time -var _ MappedNullable = &ProfileData{} - -// ProfileData struct for ProfileData -type ProfileData struct { - EnvVars map[string]string `json:"envVars"` -} - -type _ProfileData ProfileData - -// NewProfileData instantiates a new ProfileData object -// This constructor will assign default values to properties that have it defined, -// and makes sure properties required by API are set, but the set of arguments -// will change when the set of required properties is changed -func NewProfileData(envVars map[string]string) *ProfileData { - this := ProfileData{} - this.EnvVars = envVars - return &this -} - -// NewProfileDataWithDefaults instantiates a new ProfileData object -// This constructor will only assign default values to properties that have it defined, -// but it doesn't guarantee that properties required by API are set -func NewProfileDataWithDefaults() *ProfileData { - this := ProfileData{} - return &this -} - -// GetEnvVars returns the EnvVars field value -func (o *ProfileData) GetEnvVars() map[string]string { - if o == nil { - var ret map[string]string - return ret - } - - return o.EnvVars -} - -// GetEnvVarsOk returns a tuple with the EnvVars field value -// and a boolean to check if the value has been set. -func (o *ProfileData) GetEnvVarsOk() (*map[string]string, bool) { - if o == nil { - return nil, false - } - return &o.EnvVars, true -} - -// SetEnvVars sets field value -func (o *ProfileData) SetEnvVars(v map[string]string) { - o.EnvVars = v -} - -func (o ProfileData) MarshalJSON() ([]byte, error) { - toSerialize, err := o.ToMap() - if err != nil { - return []byte{}, err - } - return json.Marshal(toSerialize) -} - -func (o ProfileData) ToMap() (map[string]interface{}, error) { - toSerialize := map[string]interface{}{} - toSerialize["envVars"] = o.EnvVars - return toSerialize, nil -} - -func (o *ProfileData) UnmarshalJSON(data []byte) (err error) { - // This validates that all required properties are included in the JSON object - // by unmarshalling the object into a generic map with string keys and checking - // that every required field exists as a key in the generic map. - requiredProperties := []string{ - "envVars", - } - - allProperties := make(map[string]interface{}) - - err = json.Unmarshal(data, &allProperties) - - if err != nil { - return err - } - - for _, requiredProperty := range requiredProperties { - if _, exists := allProperties[requiredProperty]; !exists { - return fmt.Errorf("no value given for required property %v", requiredProperty) - } - } - - varProfileData := _ProfileData{} - - decoder := json.NewDecoder(bytes.NewReader(data)) - decoder.DisallowUnknownFields() - err = decoder.Decode(&varProfileData) - - if err != nil { - return err - } - - *o = ProfileData(varProfileData) - - return err -} - -type NullableProfileData struct { - value *ProfileData - isSet bool -} - -func (v NullableProfileData) Get() *ProfileData { - return v.value -} - -func (v *NullableProfileData) Set(val *ProfileData) { - v.value = val - v.isSet = true -} - -func (v NullableProfileData) IsSet() bool { - return v.isSet -} - -func (v *NullableProfileData) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableProfileData(val *ProfileData) *NullableProfileData { - return &NullableProfileData{value: val, isSet: true} -} - -func (v NullableProfileData) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableProfileData) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/pkg/apiclient/model_project.go b/pkg/apiclient/model_project.go deleted file mode 100644 index 95951f8077..0000000000 --- a/pkg/apiclient/model_project.go +++ /dev/null @@ -1,432 +0,0 @@ -/* -Daytona Server API - -Daytona Server API - -API version: v0.0.0-dev -*/ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package apiclient - -import ( - "bytes" - "encoding/json" - "fmt" -) - -// checks if the Project type satisfies the MappedNullable interface at compile time -var _ MappedNullable = &Project{} - -// Project struct for Project -type Project struct { - BuildConfig *BuildConfig `json:"buildConfig,omitempty"` - EnvVars map[string]string `json:"envVars"` - GitProviderConfigId *string `json:"gitProviderConfigId,omitempty"` - Image string `json:"image"` - Name string `json:"name"` - Repository GitRepository `json:"repository"` - State *ProjectState `json:"state,omitempty"` - Target string `json:"target"` - User string `json:"user"` - WorkspaceId string `json:"workspaceId"` -} - -type _Project Project - -// NewProject instantiates a new Project object -// This constructor will assign default values to properties that have it defined, -// and makes sure properties required by API are set, but the set of arguments -// will change when the set of required properties is changed -func NewProject(envVars map[string]string, image string, name string, repository GitRepository, target string, user string, workspaceId string) *Project { - this := Project{} - this.EnvVars = envVars - this.Image = image - this.Name = name - this.Repository = repository - this.Target = target - this.User = user - this.WorkspaceId = workspaceId - return &this -} - -// NewProjectWithDefaults instantiates a new Project object -// This constructor will only assign default values to properties that have it defined, -// but it doesn't guarantee that properties required by API are set -func NewProjectWithDefaults() *Project { - this := Project{} - return &this -} - -// GetBuildConfig returns the BuildConfig field value if set, zero value otherwise. -func (o *Project) GetBuildConfig() BuildConfig { - if o == nil || IsNil(o.BuildConfig) { - var ret BuildConfig - return ret - } - return *o.BuildConfig -} - -// GetBuildConfigOk returns a tuple with the BuildConfig field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *Project) GetBuildConfigOk() (*BuildConfig, bool) { - if o == nil || IsNil(o.BuildConfig) { - return nil, false - } - return o.BuildConfig, true -} - -// HasBuildConfig returns a boolean if a field has been set. -func (o *Project) HasBuildConfig() bool { - if o != nil && !IsNil(o.BuildConfig) { - return true - } - - return false -} - -// SetBuildConfig gets a reference to the given BuildConfig and assigns it to the BuildConfig field. -func (o *Project) SetBuildConfig(v BuildConfig) { - o.BuildConfig = &v -} - -// GetEnvVars returns the EnvVars field value -func (o *Project) GetEnvVars() map[string]string { - if o == nil { - var ret map[string]string - return ret - } - - return o.EnvVars -} - -// GetEnvVarsOk returns a tuple with the EnvVars field value -// and a boolean to check if the value has been set. -func (o *Project) GetEnvVarsOk() (*map[string]string, bool) { - if o == nil { - return nil, false - } - return &o.EnvVars, true -} - -// SetEnvVars sets field value -func (o *Project) SetEnvVars(v map[string]string) { - o.EnvVars = v -} - -// GetGitProviderConfigId returns the GitProviderConfigId field value if set, zero value otherwise. -func (o *Project) GetGitProviderConfigId() string { - if o == nil || IsNil(o.GitProviderConfigId) { - var ret string - return ret - } - return *o.GitProviderConfigId -} - -// GetGitProviderConfigIdOk returns a tuple with the GitProviderConfigId field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *Project) GetGitProviderConfigIdOk() (*string, bool) { - if o == nil || IsNil(o.GitProviderConfigId) { - return nil, false - } - return o.GitProviderConfigId, true -} - -// HasGitProviderConfigId returns a boolean if a field has been set. -func (o *Project) HasGitProviderConfigId() bool { - if o != nil && !IsNil(o.GitProviderConfigId) { - return true - } - - return false -} - -// SetGitProviderConfigId gets a reference to the given string and assigns it to the GitProviderConfigId field. -func (o *Project) SetGitProviderConfigId(v string) { - o.GitProviderConfigId = &v -} - -// GetImage returns the Image field value -func (o *Project) GetImage() string { - if o == nil { - var ret string - return ret - } - - return o.Image -} - -// GetImageOk returns a tuple with the Image field value -// and a boolean to check if the value has been set. -func (o *Project) GetImageOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.Image, true -} - -// SetImage sets field value -func (o *Project) SetImage(v string) { - o.Image = v -} - -// GetName returns the Name field value -func (o *Project) GetName() string { - if o == nil { - var ret string - return ret - } - - return o.Name -} - -// GetNameOk returns a tuple with the Name field value -// and a boolean to check if the value has been set. -func (o *Project) GetNameOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.Name, true -} - -// SetName sets field value -func (o *Project) SetName(v string) { - o.Name = v -} - -// GetRepository returns the Repository field value -func (o *Project) GetRepository() GitRepository { - if o == nil { - var ret GitRepository - return ret - } - - return o.Repository -} - -// GetRepositoryOk returns a tuple with the Repository field value -// and a boolean to check if the value has been set. -func (o *Project) GetRepositoryOk() (*GitRepository, bool) { - if o == nil { - return nil, false - } - return &o.Repository, true -} - -// SetRepository sets field value -func (o *Project) SetRepository(v GitRepository) { - o.Repository = v -} - -// GetState returns the State field value if set, zero value otherwise. -func (o *Project) GetState() ProjectState { - if o == nil || IsNil(o.State) { - var ret ProjectState - return ret - } - return *o.State -} - -// GetStateOk returns a tuple with the State field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *Project) GetStateOk() (*ProjectState, bool) { - if o == nil || IsNil(o.State) { - return nil, false - } - return o.State, true -} - -// HasState returns a boolean if a field has been set. -func (o *Project) HasState() bool { - if o != nil && !IsNil(o.State) { - return true - } - - return false -} - -// SetState gets a reference to the given ProjectState and assigns it to the State field. -func (o *Project) SetState(v ProjectState) { - o.State = &v -} - -// GetTarget returns the Target field value -func (o *Project) GetTarget() string { - if o == nil { - var ret string - return ret - } - - return o.Target -} - -// GetTargetOk returns a tuple with the Target field value -// and a boolean to check if the value has been set. -func (o *Project) GetTargetOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.Target, true -} - -// SetTarget sets field value -func (o *Project) SetTarget(v string) { - o.Target = v -} - -// GetUser returns the User field value -func (o *Project) GetUser() string { - if o == nil { - var ret string - return ret - } - - return o.User -} - -// GetUserOk returns a tuple with the User field value -// and a boolean to check if the value has been set. -func (o *Project) GetUserOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.User, true -} - -// SetUser sets field value -func (o *Project) SetUser(v string) { - o.User = v -} - -// GetWorkspaceId returns the WorkspaceId field value -func (o *Project) GetWorkspaceId() string { - if o == nil { - var ret string - return ret - } - - return o.WorkspaceId -} - -// GetWorkspaceIdOk returns a tuple with the WorkspaceId field value -// and a boolean to check if the value has been set. -func (o *Project) GetWorkspaceIdOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.WorkspaceId, true -} - -// SetWorkspaceId sets field value -func (o *Project) SetWorkspaceId(v string) { - o.WorkspaceId = v -} - -func (o Project) MarshalJSON() ([]byte, error) { - toSerialize, err := o.ToMap() - if err != nil { - return []byte{}, err - } - return json.Marshal(toSerialize) -} - -func (o Project) ToMap() (map[string]interface{}, error) { - toSerialize := map[string]interface{}{} - if !IsNil(o.BuildConfig) { - toSerialize["buildConfig"] = o.BuildConfig - } - toSerialize["envVars"] = o.EnvVars - if !IsNil(o.GitProviderConfigId) { - toSerialize["gitProviderConfigId"] = o.GitProviderConfigId - } - toSerialize["image"] = o.Image - toSerialize["name"] = o.Name - toSerialize["repository"] = o.Repository - if !IsNil(o.State) { - toSerialize["state"] = o.State - } - toSerialize["target"] = o.Target - toSerialize["user"] = o.User - toSerialize["workspaceId"] = o.WorkspaceId - return toSerialize, nil -} - -func (o *Project) UnmarshalJSON(data []byte) (err error) { - // This validates that all required properties are included in the JSON object - // by unmarshalling the object into a generic map with string keys and checking - // that every required field exists as a key in the generic map. - requiredProperties := []string{ - "envVars", - "image", - "name", - "repository", - "target", - "user", - "workspaceId", - } - - allProperties := make(map[string]interface{}) - - err = json.Unmarshal(data, &allProperties) - - if err != nil { - return err - } - - for _, requiredProperty := range requiredProperties { - if _, exists := allProperties[requiredProperty]; !exists { - return fmt.Errorf("no value given for required property %v", requiredProperty) - } - } - - varProject := _Project{} - - decoder := json.NewDecoder(bytes.NewReader(data)) - decoder.DisallowUnknownFields() - err = decoder.Decode(&varProject) - - if err != nil { - return err - } - - *o = Project(varProject) - - return err -} - -type NullableProject struct { - value *Project - isSet bool -} - -func (v NullableProject) Get() *Project { - return v.value -} - -func (v *NullableProject) Set(val *Project) { - v.value = val - v.isSet = true -} - -func (v NullableProject) IsSet() bool { - return v.isSet -} - -func (v *NullableProject) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableProject(val *Project) *NullableProject { - return &NullableProject{value: val, isSet: true} -} - -func (v NullableProject) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableProject) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/pkg/apiclient/model_project_info.go b/pkg/apiclient/model_project_info.go deleted file mode 100644 index 15d0072ba8..0000000000 --- a/pkg/apiclient/model_project_info.go +++ /dev/null @@ -1,276 +0,0 @@ -/* -Daytona Server API - -Daytona Server API - -API version: v0.0.0-dev -*/ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package apiclient - -import ( - "bytes" - "encoding/json" - "fmt" -) - -// checks if the ProjectInfo type satisfies the MappedNullable interface at compile time -var _ MappedNullable = &ProjectInfo{} - -// ProjectInfo struct for ProjectInfo -type ProjectInfo struct { - Created string `json:"created"` - IsRunning bool `json:"isRunning"` - Name string `json:"name"` - ProviderMetadata *string `json:"providerMetadata,omitempty"` - WorkspaceId string `json:"workspaceId"` -} - -type _ProjectInfo ProjectInfo - -// NewProjectInfo instantiates a new ProjectInfo object -// This constructor will assign default values to properties that have it defined, -// and makes sure properties required by API are set, but the set of arguments -// will change when the set of required properties is changed -func NewProjectInfo(created string, isRunning bool, name string, workspaceId string) *ProjectInfo { - this := ProjectInfo{} - this.Created = created - this.IsRunning = isRunning - this.Name = name - this.WorkspaceId = workspaceId - return &this -} - -// NewProjectInfoWithDefaults instantiates a new ProjectInfo object -// This constructor will only assign default values to properties that have it defined, -// but it doesn't guarantee that properties required by API are set -func NewProjectInfoWithDefaults() *ProjectInfo { - this := ProjectInfo{} - return &this -} - -// GetCreated returns the Created field value -func (o *ProjectInfo) GetCreated() string { - if o == nil { - var ret string - return ret - } - - return o.Created -} - -// GetCreatedOk returns a tuple with the Created field value -// and a boolean to check if the value has been set. -func (o *ProjectInfo) GetCreatedOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.Created, true -} - -// SetCreated sets field value -func (o *ProjectInfo) SetCreated(v string) { - o.Created = v -} - -// GetIsRunning returns the IsRunning field value -func (o *ProjectInfo) GetIsRunning() bool { - if o == nil { - var ret bool - return ret - } - - return o.IsRunning -} - -// GetIsRunningOk returns a tuple with the IsRunning field value -// and a boolean to check if the value has been set. -func (o *ProjectInfo) GetIsRunningOk() (*bool, bool) { - if o == nil { - return nil, false - } - return &o.IsRunning, true -} - -// SetIsRunning sets field value -func (o *ProjectInfo) SetIsRunning(v bool) { - o.IsRunning = v -} - -// GetName returns the Name field value -func (o *ProjectInfo) GetName() string { - if o == nil { - var ret string - return ret - } - - return o.Name -} - -// GetNameOk returns a tuple with the Name field value -// and a boolean to check if the value has been set. -func (o *ProjectInfo) GetNameOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.Name, true -} - -// SetName sets field value -func (o *ProjectInfo) SetName(v string) { - o.Name = v -} - -// GetProviderMetadata returns the ProviderMetadata field value if set, zero value otherwise. -func (o *ProjectInfo) GetProviderMetadata() string { - if o == nil || IsNil(o.ProviderMetadata) { - var ret string - return ret - } - return *o.ProviderMetadata -} - -// GetProviderMetadataOk returns a tuple with the ProviderMetadata field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *ProjectInfo) GetProviderMetadataOk() (*string, bool) { - if o == nil || IsNil(o.ProviderMetadata) { - return nil, false - } - return o.ProviderMetadata, true -} - -// HasProviderMetadata returns a boolean if a field has been set. -func (o *ProjectInfo) HasProviderMetadata() bool { - if o != nil && !IsNil(o.ProviderMetadata) { - return true - } - - return false -} - -// SetProviderMetadata gets a reference to the given string and assigns it to the ProviderMetadata field. -func (o *ProjectInfo) SetProviderMetadata(v string) { - o.ProviderMetadata = &v -} - -// GetWorkspaceId returns the WorkspaceId field value -func (o *ProjectInfo) GetWorkspaceId() string { - if o == nil { - var ret string - return ret - } - - return o.WorkspaceId -} - -// GetWorkspaceIdOk returns a tuple with the WorkspaceId field value -// and a boolean to check if the value has been set. -func (o *ProjectInfo) GetWorkspaceIdOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.WorkspaceId, true -} - -// SetWorkspaceId sets field value -func (o *ProjectInfo) SetWorkspaceId(v string) { - o.WorkspaceId = v -} - -func (o ProjectInfo) MarshalJSON() ([]byte, error) { - toSerialize, err := o.ToMap() - if err != nil { - return []byte{}, err - } - return json.Marshal(toSerialize) -} - -func (o ProjectInfo) ToMap() (map[string]interface{}, error) { - toSerialize := map[string]interface{}{} - toSerialize["created"] = o.Created - toSerialize["isRunning"] = o.IsRunning - toSerialize["name"] = o.Name - if !IsNil(o.ProviderMetadata) { - toSerialize["providerMetadata"] = o.ProviderMetadata - } - toSerialize["workspaceId"] = o.WorkspaceId - return toSerialize, nil -} - -func (o *ProjectInfo) UnmarshalJSON(data []byte) (err error) { - // This validates that all required properties are included in the JSON object - // by unmarshalling the object into a generic map with string keys and checking - // that every required field exists as a key in the generic map. - requiredProperties := []string{ - "created", - "isRunning", - "name", - "workspaceId", - } - - allProperties := make(map[string]interface{}) - - err = json.Unmarshal(data, &allProperties) - - if err != nil { - return err - } - - for _, requiredProperty := range requiredProperties { - if _, exists := allProperties[requiredProperty]; !exists { - return fmt.Errorf("no value given for required property %v", requiredProperty) - } - } - - varProjectInfo := _ProjectInfo{} - - decoder := json.NewDecoder(bytes.NewReader(data)) - decoder.DisallowUnknownFields() - err = decoder.Decode(&varProjectInfo) - - if err != nil { - return err - } - - *o = ProjectInfo(varProjectInfo) - - return err -} - -type NullableProjectInfo struct { - value *ProjectInfo - isSet bool -} - -func (v NullableProjectInfo) Get() *ProjectInfo { - return v.value -} - -func (v *NullableProjectInfo) Set(val *ProjectInfo) { - v.value = val - v.isSet = true -} - -func (v NullableProjectInfo) IsSet() bool { - return v.isSet -} - -func (v *NullableProjectInfo) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableProjectInfo(val *ProjectInfo) *NullableProjectInfo { - return &NullableProjectInfo{value: val, isSet: true} -} - -func (v NullableProjectInfo) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableProjectInfo) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/pkg/apiclient/model_provider.go b/pkg/apiclient/model_provider.go deleted file mode 100644 index b5c025dfba..0000000000 --- a/pkg/apiclient/model_provider.go +++ /dev/null @@ -1,220 +0,0 @@ -/* -Daytona Server API - -Daytona Server API - -API version: v0.0.0-dev -*/ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package apiclient - -import ( - "bytes" - "encoding/json" - "fmt" -) - -// checks if the Provider type satisfies the MappedNullable interface at compile time -var _ MappedNullable = &Provider{} - -// Provider struct for Provider -type Provider struct { - Label *string `json:"label,omitempty"` - Name string `json:"name"` - Version string `json:"version"` -} - -type _Provider Provider - -// NewProvider instantiates a new Provider object -// This constructor will assign default values to properties that have it defined, -// and makes sure properties required by API are set, but the set of arguments -// will change when the set of required properties is changed -func NewProvider(name string, version string) *Provider { - this := Provider{} - this.Name = name - this.Version = version - return &this -} - -// NewProviderWithDefaults instantiates a new Provider object -// This constructor will only assign default values to properties that have it defined, -// but it doesn't guarantee that properties required by API are set -func NewProviderWithDefaults() *Provider { - this := Provider{} - return &this -} - -// GetLabel returns the Label field value if set, zero value otherwise. -func (o *Provider) GetLabel() string { - if o == nil || IsNil(o.Label) { - var ret string - return ret - } - return *o.Label -} - -// GetLabelOk returns a tuple with the Label field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *Provider) GetLabelOk() (*string, bool) { - if o == nil || IsNil(o.Label) { - return nil, false - } - return o.Label, true -} - -// HasLabel returns a boolean if a field has been set. -func (o *Provider) HasLabel() bool { - if o != nil && !IsNil(o.Label) { - return true - } - - return false -} - -// SetLabel gets a reference to the given string and assigns it to the Label field. -func (o *Provider) SetLabel(v string) { - o.Label = &v -} - -// GetName returns the Name field value -func (o *Provider) GetName() string { - if o == nil { - var ret string - return ret - } - - return o.Name -} - -// GetNameOk returns a tuple with the Name field value -// and a boolean to check if the value has been set. -func (o *Provider) GetNameOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.Name, true -} - -// SetName sets field value -func (o *Provider) SetName(v string) { - o.Name = v -} - -// GetVersion returns the Version field value -func (o *Provider) GetVersion() string { - if o == nil { - var ret string - return ret - } - - return o.Version -} - -// GetVersionOk returns a tuple with the Version field value -// and a boolean to check if the value has been set. -func (o *Provider) GetVersionOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.Version, true -} - -// SetVersion sets field value -func (o *Provider) SetVersion(v string) { - o.Version = v -} - -func (o Provider) MarshalJSON() ([]byte, error) { - toSerialize, err := o.ToMap() - if err != nil { - return []byte{}, err - } - return json.Marshal(toSerialize) -} - -func (o Provider) ToMap() (map[string]interface{}, error) { - toSerialize := map[string]interface{}{} - if !IsNil(o.Label) { - toSerialize["label"] = o.Label - } - toSerialize["name"] = o.Name - toSerialize["version"] = o.Version - return toSerialize, nil -} - -func (o *Provider) UnmarshalJSON(data []byte) (err error) { - // This validates that all required properties are included in the JSON object - // by unmarshalling the object into a generic map with string keys and checking - // that every required field exists as a key in the generic map. - requiredProperties := []string{ - "name", - "version", - } - - allProperties := make(map[string]interface{}) - - err = json.Unmarshal(data, &allProperties) - - if err != nil { - return err - } - - for _, requiredProperty := range requiredProperties { - if _, exists := allProperties[requiredProperty]; !exists { - return fmt.Errorf("no value given for required property %v", requiredProperty) - } - } - - varProvider := _Provider{} - - decoder := json.NewDecoder(bytes.NewReader(data)) - decoder.DisallowUnknownFields() - err = decoder.Decode(&varProvider) - - if err != nil { - return err - } - - *o = Provider(varProvider) - - return err -} - -type NullableProvider struct { - value *Provider - isSet bool -} - -func (v NullableProvider) Get() *Provider { - return v.value -} - -func (v *NullableProvider) Set(val *Provider) { - v.value = val - v.isSet = true -} - -func (v NullableProvider) IsSet() bool { - return v.isSet -} - -func (v *NullableProvider) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableProvider(val *Provider) *NullableProvider { - return &NullableProvider{value: val, isSet: true} -} - -func (v NullableProvider) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableProvider) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/pkg/apiclient/model_provider_provider_info.go b/pkg/apiclient/model_provider_dto.go similarity index 58% rename from pkg/apiclient/model_provider_provider_info.go rename to pkg/apiclient/model_provider_dto.go index 070852d9c1..5db419aee0 100644 --- a/pkg/apiclient/model_provider_provider_info.go +++ b/pkg/apiclient/model_provider_dto.go @@ -16,39 +16,41 @@ import ( "fmt" ) -// checks if the ProviderProviderInfo type satisfies the MappedNullable interface at compile time -var _ MappedNullable = &ProviderProviderInfo{} +// checks if the ProviderDTO type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &ProviderDTO{} -// ProviderProviderInfo struct for ProviderProviderInfo -type ProviderProviderInfo struct { +// ProviderDTO struct for ProviderDTO +type ProviderDTO struct { Label *string `json:"label,omitempty"` + Latest bool `json:"latest"` Name string `json:"name"` Version string `json:"version"` } -type _ProviderProviderInfo ProviderProviderInfo +type _ProviderDTO ProviderDTO -// NewProviderProviderInfo instantiates a new ProviderProviderInfo object +// NewProviderDTO instantiates a new ProviderDTO object // This constructor will assign default values to properties that have it defined, // and makes sure properties required by API are set, but the set of arguments // will change when the set of required properties is changed -func NewProviderProviderInfo(name string, version string) *ProviderProviderInfo { - this := ProviderProviderInfo{} +func NewProviderDTO(latest bool, name string, version string) *ProviderDTO { + this := ProviderDTO{} + this.Latest = latest this.Name = name this.Version = version return &this } -// NewProviderProviderInfoWithDefaults instantiates a new ProviderProviderInfo object +// NewProviderDTOWithDefaults instantiates a new ProviderDTO object // This constructor will only assign default values to properties that have it defined, // but it doesn't guarantee that properties required by API are set -func NewProviderProviderInfoWithDefaults() *ProviderProviderInfo { - this := ProviderProviderInfo{} +func NewProviderDTOWithDefaults() *ProviderDTO { + this := ProviderDTO{} return &this } // GetLabel returns the Label field value if set, zero value otherwise. -func (o *ProviderProviderInfo) GetLabel() string { +func (o *ProviderDTO) GetLabel() string { if o == nil || IsNil(o.Label) { var ret string return ret @@ -58,7 +60,7 @@ func (o *ProviderProviderInfo) GetLabel() string { // GetLabelOk returns a tuple with the Label field value if set, nil otherwise // and a boolean to check if the value has been set. -func (o *ProviderProviderInfo) GetLabelOk() (*string, bool) { +func (o *ProviderDTO) GetLabelOk() (*string, bool) { if o == nil || IsNil(o.Label) { return nil, false } @@ -66,7 +68,7 @@ func (o *ProviderProviderInfo) GetLabelOk() (*string, bool) { } // HasLabel returns a boolean if a field has been set. -func (o *ProviderProviderInfo) HasLabel() bool { +func (o *ProviderDTO) HasLabel() bool { if o != nil && !IsNil(o.Label) { return true } @@ -75,12 +77,36 @@ func (o *ProviderProviderInfo) HasLabel() bool { } // SetLabel gets a reference to the given string and assigns it to the Label field. -func (o *ProviderProviderInfo) SetLabel(v string) { +func (o *ProviderDTO) SetLabel(v string) { o.Label = &v } +// GetLatest returns the Latest field value +func (o *ProviderDTO) GetLatest() bool { + if o == nil { + var ret bool + return ret + } + + return o.Latest +} + +// GetLatestOk returns a tuple with the Latest field value +// and a boolean to check if the value has been set. +func (o *ProviderDTO) GetLatestOk() (*bool, bool) { + if o == nil { + return nil, false + } + return &o.Latest, true +} + +// SetLatest sets field value +func (o *ProviderDTO) SetLatest(v bool) { + o.Latest = v +} + // GetName returns the Name field value -func (o *ProviderProviderInfo) GetName() string { +func (o *ProviderDTO) GetName() string { if o == nil { var ret string return ret @@ -91,7 +117,7 @@ func (o *ProviderProviderInfo) GetName() string { // GetNameOk returns a tuple with the Name field value // and a boolean to check if the value has been set. -func (o *ProviderProviderInfo) GetNameOk() (*string, bool) { +func (o *ProviderDTO) GetNameOk() (*string, bool) { if o == nil { return nil, false } @@ -99,12 +125,12 @@ func (o *ProviderProviderInfo) GetNameOk() (*string, bool) { } // SetName sets field value -func (o *ProviderProviderInfo) SetName(v string) { +func (o *ProviderDTO) SetName(v string) { o.Name = v } // GetVersion returns the Version field value -func (o *ProviderProviderInfo) GetVersion() string { +func (o *ProviderDTO) GetVersion() string { if o == nil { var ret string return ret @@ -115,7 +141,7 @@ func (o *ProviderProviderInfo) GetVersion() string { // GetVersionOk returns a tuple with the Version field value // and a boolean to check if the value has been set. -func (o *ProviderProviderInfo) GetVersionOk() (*string, bool) { +func (o *ProviderDTO) GetVersionOk() (*string, bool) { if o == nil { return nil, false } @@ -123,11 +149,11 @@ func (o *ProviderProviderInfo) GetVersionOk() (*string, bool) { } // SetVersion sets field value -func (o *ProviderProviderInfo) SetVersion(v string) { +func (o *ProviderDTO) SetVersion(v string) { o.Version = v } -func (o ProviderProviderInfo) MarshalJSON() ([]byte, error) { +func (o ProviderDTO) MarshalJSON() ([]byte, error) { toSerialize, err := o.ToMap() if err != nil { return []byte{}, err @@ -135,21 +161,23 @@ func (o ProviderProviderInfo) MarshalJSON() ([]byte, error) { return json.Marshal(toSerialize) } -func (o ProviderProviderInfo) ToMap() (map[string]interface{}, error) { +func (o ProviderDTO) ToMap() (map[string]interface{}, error) { toSerialize := map[string]interface{}{} if !IsNil(o.Label) { toSerialize["label"] = o.Label } + toSerialize["latest"] = o.Latest toSerialize["name"] = o.Name toSerialize["version"] = o.Version return toSerialize, nil } -func (o *ProviderProviderInfo) UnmarshalJSON(data []byte) (err error) { +func (o *ProviderDTO) UnmarshalJSON(data []byte) (err error) { // This validates that all required properties are included in the JSON object // by unmarshalling the object into a generic map with string keys and checking // that every required field exists as a key in the generic map. requiredProperties := []string{ + "latest", "name", "version", } @@ -168,53 +196,53 @@ func (o *ProviderProviderInfo) UnmarshalJSON(data []byte) (err error) { } } - varProviderProviderInfo := _ProviderProviderInfo{} + varProviderDTO := _ProviderDTO{} decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() - err = decoder.Decode(&varProviderProviderInfo) + err = decoder.Decode(&varProviderDTO) if err != nil { return err } - *o = ProviderProviderInfo(varProviderProviderInfo) + *o = ProviderDTO(varProviderDTO) return err } -type NullableProviderProviderInfo struct { - value *ProviderProviderInfo +type NullableProviderDTO struct { + value *ProviderDTO isSet bool } -func (v NullableProviderProviderInfo) Get() *ProviderProviderInfo { +func (v NullableProviderDTO) Get() *ProviderDTO { return v.value } -func (v *NullableProviderProviderInfo) Set(val *ProviderProviderInfo) { +func (v *NullableProviderDTO) Set(val *ProviderDTO) { v.value = val v.isSet = true } -func (v NullableProviderProviderInfo) IsSet() bool { +func (v NullableProviderDTO) IsSet() bool { return v.isSet } -func (v *NullableProviderProviderInfo) Unset() { +func (v *NullableProviderDTO) Unset() { v.value = nil v.isSet = false } -func NewNullableProviderProviderInfo(val *ProviderProviderInfo) *NullableProviderProviderInfo { - return &NullableProviderProviderInfo{value: val, isSet: true} +func NewNullableProviderDTO(val *ProviderDTO) *NullableProviderDTO { + return &NullableProviderDTO{value: val, isSet: true} } -func (v NullableProviderProviderInfo) MarshalJSON() ([]byte, error) { +func (v NullableProviderDTO) MarshalJSON() ([]byte, error) { return json.Marshal(v.value) } -func (v *NullableProviderProviderInfo) UnmarshalJSON(src []byte) error { +func (v *NullableProviderDTO) UnmarshalJSON(src []byte) error { v.isSet = true return json.Unmarshal(src, &v.value) } diff --git a/pkg/apiclient/model_provider_info.go b/pkg/apiclient/model_provider_info.go new file mode 100644 index 0000000000..0f1d3ad2b1 --- /dev/null +++ b/pkg/apiclient/model_provider_info.go @@ -0,0 +1,340 @@ +/* +Daytona Server API + +Daytona Server API + +API version: v0.0.0-dev +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package apiclient + +import ( + "bytes" + "encoding/json" + "fmt" +) + +// checks if the ProviderInfo type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &ProviderInfo{} + +// ProviderInfo struct for ProviderInfo +type ProviderInfo struct { + AgentlessTarget *bool `json:"agentlessTarget,omitempty"` + Label *string `json:"label,omitempty"` + Name string `json:"name"` + RunnerId string `json:"runnerId"` + RunnerName string `json:"runnerName"` + TargetConfigManifest map[string]TargetConfigProperty `json:"targetConfigManifest"` + Version string `json:"version"` +} + +type _ProviderInfo ProviderInfo + +// NewProviderInfo instantiates a new ProviderInfo object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewProviderInfo(name string, runnerId string, runnerName string, targetConfigManifest map[string]TargetConfigProperty, version string) *ProviderInfo { + this := ProviderInfo{} + this.Name = name + this.RunnerId = runnerId + this.RunnerName = runnerName + this.TargetConfigManifest = targetConfigManifest + this.Version = version + return &this +} + +// NewProviderInfoWithDefaults instantiates a new ProviderInfo object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewProviderInfoWithDefaults() *ProviderInfo { + this := ProviderInfo{} + return &this +} + +// GetAgentlessTarget returns the AgentlessTarget field value if set, zero value otherwise. +func (o *ProviderInfo) GetAgentlessTarget() bool { + if o == nil || IsNil(o.AgentlessTarget) { + var ret bool + return ret + } + return *o.AgentlessTarget +} + +// GetAgentlessTargetOk returns a tuple with the AgentlessTarget field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *ProviderInfo) GetAgentlessTargetOk() (*bool, bool) { + if o == nil || IsNil(o.AgentlessTarget) { + return nil, false + } + return o.AgentlessTarget, true +} + +// HasAgentlessTarget returns a boolean if a field has been set. +func (o *ProviderInfo) HasAgentlessTarget() bool { + if o != nil && !IsNil(o.AgentlessTarget) { + return true + } + + return false +} + +// SetAgentlessTarget gets a reference to the given bool and assigns it to the AgentlessTarget field. +func (o *ProviderInfo) SetAgentlessTarget(v bool) { + o.AgentlessTarget = &v +} + +// GetLabel returns the Label field value if set, zero value otherwise. +func (o *ProviderInfo) GetLabel() string { + if o == nil || IsNil(o.Label) { + var ret string + return ret + } + return *o.Label +} + +// GetLabelOk returns a tuple with the Label field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *ProviderInfo) GetLabelOk() (*string, bool) { + if o == nil || IsNil(o.Label) { + return nil, false + } + return o.Label, true +} + +// HasLabel returns a boolean if a field has been set. +func (o *ProviderInfo) HasLabel() bool { + if o != nil && !IsNil(o.Label) { + return true + } + + return false +} + +// SetLabel gets a reference to the given string and assigns it to the Label field. +func (o *ProviderInfo) SetLabel(v string) { + o.Label = &v +} + +// GetName returns the Name field value +func (o *ProviderInfo) GetName() string { + if o == nil { + var ret string + return ret + } + + return o.Name +} + +// GetNameOk returns a tuple with the Name field value +// and a boolean to check if the value has been set. +func (o *ProviderInfo) GetNameOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Name, true +} + +// SetName sets field value +func (o *ProviderInfo) SetName(v string) { + o.Name = v +} + +// GetRunnerId returns the RunnerId field value +func (o *ProviderInfo) GetRunnerId() string { + if o == nil { + var ret string + return ret + } + + return o.RunnerId +} + +// GetRunnerIdOk returns a tuple with the RunnerId field value +// and a boolean to check if the value has been set. +func (o *ProviderInfo) GetRunnerIdOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.RunnerId, true +} + +// SetRunnerId sets field value +func (o *ProviderInfo) SetRunnerId(v string) { + o.RunnerId = v +} + +// GetRunnerName returns the RunnerName field value +func (o *ProviderInfo) GetRunnerName() string { + if o == nil { + var ret string + return ret + } + + return o.RunnerName +} + +// GetRunnerNameOk returns a tuple with the RunnerName field value +// and a boolean to check if the value has been set. +func (o *ProviderInfo) GetRunnerNameOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.RunnerName, true +} + +// SetRunnerName sets field value +func (o *ProviderInfo) SetRunnerName(v string) { + o.RunnerName = v +} + +// GetTargetConfigManifest returns the TargetConfigManifest field value +func (o *ProviderInfo) GetTargetConfigManifest() map[string]TargetConfigProperty { + if o == nil { + var ret map[string]TargetConfigProperty + return ret + } + + return o.TargetConfigManifest +} + +// GetTargetConfigManifestOk returns a tuple with the TargetConfigManifest field value +// and a boolean to check if the value has been set. +func (o *ProviderInfo) GetTargetConfigManifestOk() (*map[string]TargetConfigProperty, bool) { + if o == nil { + return nil, false + } + return &o.TargetConfigManifest, true +} + +// SetTargetConfigManifest sets field value +func (o *ProviderInfo) SetTargetConfigManifest(v map[string]TargetConfigProperty) { + o.TargetConfigManifest = v +} + +// GetVersion returns the Version field value +func (o *ProviderInfo) GetVersion() string { + if o == nil { + var ret string + return ret + } + + return o.Version +} + +// GetVersionOk returns a tuple with the Version field value +// and a boolean to check if the value has been set. +func (o *ProviderInfo) GetVersionOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Version, true +} + +// SetVersion sets field value +func (o *ProviderInfo) SetVersion(v string) { + o.Version = v +} + +func (o ProviderInfo) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o ProviderInfo) ToMap() (map[string]interface{}, error) { + toSerialize := map[string]interface{}{} + if !IsNil(o.AgentlessTarget) { + toSerialize["agentlessTarget"] = o.AgentlessTarget + } + if !IsNil(o.Label) { + toSerialize["label"] = o.Label + } + toSerialize["name"] = o.Name + toSerialize["runnerId"] = o.RunnerId + toSerialize["runnerName"] = o.RunnerName + toSerialize["targetConfigManifest"] = o.TargetConfigManifest + toSerialize["version"] = o.Version + return toSerialize, nil +} + +func (o *ProviderInfo) UnmarshalJSON(data []byte) (err error) { + // This validates that all required properties are included in the JSON object + // by unmarshalling the object into a generic map with string keys and checking + // that every required field exists as a key in the generic map. + requiredProperties := []string{ + "name", + "runnerId", + "runnerName", + "targetConfigManifest", + "version", + } + + allProperties := make(map[string]interface{}) + + err = json.Unmarshal(data, &allProperties) + + if err != nil { + return err + } + + for _, requiredProperty := range requiredProperties { + if _, exists := allProperties[requiredProperty]; !exists { + return fmt.Errorf("no value given for required property %v", requiredProperty) + } + } + + varProviderInfo := _ProviderInfo{} + + decoder := json.NewDecoder(bytes.NewReader(data)) + decoder.DisallowUnknownFields() + err = decoder.Decode(&varProviderInfo) + + if err != nil { + return err + } + + *o = ProviderInfo(varProviderInfo) + + return err +} + +type NullableProviderInfo struct { + value *ProviderInfo + isSet bool +} + +func (v NullableProviderInfo) Get() *ProviderInfo { + return v.value +} + +func (v *NullableProviderInfo) Set(val *ProviderInfo) { + v.value = val + v.isSet = true +} + +func (v NullableProviderInfo) IsSet() bool { + return v.isSet +} + +func (v *NullableProviderInfo) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableProviderInfo(val *ProviderInfo) *NullableProviderInfo { + return &NullableProviderInfo{value: val, isSet: true} +} + +func (v NullableProviderInfo) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableProviderInfo) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/pkg/apiclient/model_provider_provider_target_property_type.go b/pkg/apiclient/model_provider_provider_target_property_type.go deleted file mode 100644 index 09210e35c5..0000000000 --- a/pkg/apiclient/model_provider_provider_target_property_type.go +++ /dev/null @@ -1,118 +0,0 @@ -/* -Daytona Server API - -Daytona Server API - -API version: v0.0.0-dev -*/ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package apiclient - -import ( - "encoding/json" - "fmt" -) - -// ProviderProviderTargetPropertyType the model 'ProviderProviderTargetPropertyType' -type ProviderProviderTargetPropertyType string - -// List of provider.ProviderTargetPropertyType -const ( - ProviderTargetPropertyTypeString ProviderProviderTargetPropertyType = "string" - ProviderTargetPropertyTypeOption ProviderProviderTargetPropertyType = "option" - ProviderTargetPropertyTypeBoolean ProviderProviderTargetPropertyType = "boolean" - ProviderTargetPropertyTypeInt ProviderProviderTargetPropertyType = "int" - ProviderTargetPropertyTypeFloat ProviderProviderTargetPropertyType = "float" - ProviderTargetPropertyTypeFilePath ProviderProviderTargetPropertyType = "file-path" -) - -// All allowed values of ProviderProviderTargetPropertyType enum -var AllowedProviderProviderTargetPropertyTypeEnumValues = []ProviderProviderTargetPropertyType{ - "string", - "option", - "boolean", - "int", - "float", - "file-path", -} - -func (v *ProviderProviderTargetPropertyType) UnmarshalJSON(src []byte) error { - var value string - err := json.Unmarshal(src, &value) - if err != nil { - return err - } - enumTypeValue := ProviderProviderTargetPropertyType(value) - for _, existing := range AllowedProviderProviderTargetPropertyTypeEnumValues { - if existing == enumTypeValue { - *v = enumTypeValue - return nil - } - } - - return fmt.Errorf("%+v is not a valid ProviderProviderTargetPropertyType", value) -} - -// NewProviderProviderTargetPropertyTypeFromValue returns a pointer to a valid ProviderProviderTargetPropertyType -// for the value passed as argument, or an error if the value passed is not allowed by the enum -func NewProviderProviderTargetPropertyTypeFromValue(v string) (*ProviderProviderTargetPropertyType, error) { - ev := ProviderProviderTargetPropertyType(v) - if ev.IsValid() { - return &ev, nil - } else { - return nil, fmt.Errorf("invalid value '%v' for ProviderProviderTargetPropertyType: valid values are %v", v, AllowedProviderProviderTargetPropertyTypeEnumValues) - } -} - -// IsValid return true if the value is valid for the enum, false otherwise -func (v ProviderProviderTargetPropertyType) IsValid() bool { - for _, existing := range AllowedProviderProviderTargetPropertyTypeEnumValues { - if existing == v { - return true - } - } - return false -} - -// Ptr returns reference to provider.ProviderTargetPropertyType value -func (v ProviderProviderTargetPropertyType) Ptr() *ProviderProviderTargetPropertyType { - return &v -} - -type NullableProviderProviderTargetPropertyType struct { - value *ProviderProviderTargetPropertyType - isSet bool -} - -func (v NullableProviderProviderTargetPropertyType) Get() *ProviderProviderTargetPropertyType { - return v.value -} - -func (v *NullableProviderProviderTargetPropertyType) Set(val *ProviderProviderTargetPropertyType) { - v.value = val - v.isSet = true -} - -func (v NullableProviderProviderTargetPropertyType) IsSet() bool { - return v.isSet -} - -func (v *NullableProviderProviderTargetPropertyType) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableProviderProviderTargetPropertyType(val *ProviderProviderTargetPropertyType) *NullableProviderProviderTargetPropertyType { - return &NullableProviderProviderTargetPropertyType{value: val, isSet: true} -} - -func (v NullableProviderProviderTargetPropertyType) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableProviderProviderTargetPropertyType) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/pkg/apiclient/model_resource_state.go b/pkg/apiclient/model_resource_state.go new file mode 100644 index 0000000000..93a79407d9 --- /dev/null +++ b/pkg/apiclient/model_resource_state.go @@ -0,0 +1,220 @@ +/* +Daytona Server API + +Daytona Server API + +API version: v0.0.0-dev +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package apiclient + +import ( + "bytes" + "encoding/json" + "fmt" +) + +// checks if the ResourceState type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &ResourceState{} + +// ResourceState struct for ResourceState +type ResourceState struct { + Error *string `json:"error,omitempty"` + Name ModelsResourceStateName `json:"name"` + UpdatedAt string `json:"updatedAt"` +} + +type _ResourceState ResourceState + +// NewResourceState instantiates a new ResourceState object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewResourceState(name ModelsResourceStateName, updatedAt string) *ResourceState { + this := ResourceState{} + this.Name = name + this.UpdatedAt = updatedAt + return &this +} + +// NewResourceStateWithDefaults instantiates a new ResourceState object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewResourceStateWithDefaults() *ResourceState { + this := ResourceState{} + return &this +} + +// GetError returns the Error field value if set, zero value otherwise. +func (o *ResourceState) GetError() string { + if o == nil || IsNil(o.Error) { + var ret string + return ret + } + return *o.Error +} + +// GetErrorOk returns a tuple with the Error field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *ResourceState) GetErrorOk() (*string, bool) { + if o == nil || IsNil(o.Error) { + return nil, false + } + return o.Error, true +} + +// HasError returns a boolean if a field has been set. +func (o *ResourceState) HasError() bool { + if o != nil && !IsNil(o.Error) { + return true + } + + return false +} + +// SetError gets a reference to the given string and assigns it to the Error field. +func (o *ResourceState) SetError(v string) { + o.Error = &v +} + +// GetName returns the Name field value +func (o *ResourceState) GetName() ModelsResourceStateName { + if o == nil { + var ret ModelsResourceStateName + return ret + } + + return o.Name +} + +// GetNameOk returns a tuple with the Name field value +// and a boolean to check if the value has been set. +func (o *ResourceState) GetNameOk() (*ModelsResourceStateName, bool) { + if o == nil { + return nil, false + } + return &o.Name, true +} + +// SetName sets field value +func (o *ResourceState) SetName(v ModelsResourceStateName) { + o.Name = v +} + +// GetUpdatedAt returns the UpdatedAt field value +func (o *ResourceState) GetUpdatedAt() string { + if o == nil { + var ret string + return ret + } + + return o.UpdatedAt +} + +// GetUpdatedAtOk returns a tuple with the UpdatedAt field value +// and a boolean to check if the value has been set. +func (o *ResourceState) GetUpdatedAtOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.UpdatedAt, true +} + +// SetUpdatedAt sets field value +func (o *ResourceState) SetUpdatedAt(v string) { + o.UpdatedAt = v +} + +func (o ResourceState) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o ResourceState) ToMap() (map[string]interface{}, error) { + toSerialize := map[string]interface{}{} + if !IsNil(o.Error) { + toSerialize["error"] = o.Error + } + toSerialize["name"] = o.Name + toSerialize["updatedAt"] = o.UpdatedAt + return toSerialize, nil +} + +func (o *ResourceState) UnmarshalJSON(data []byte) (err error) { + // This validates that all required properties are included in the JSON object + // by unmarshalling the object into a generic map with string keys and checking + // that every required field exists as a key in the generic map. + requiredProperties := []string{ + "name", + "updatedAt", + } + + allProperties := make(map[string]interface{}) + + err = json.Unmarshal(data, &allProperties) + + if err != nil { + return err + } + + for _, requiredProperty := range requiredProperties { + if _, exists := allProperties[requiredProperty]; !exists { + return fmt.Errorf("no value given for required property %v", requiredProperty) + } + } + + varResourceState := _ResourceState{} + + decoder := json.NewDecoder(bytes.NewReader(data)) + decoder.DisallowUnknownFields() + err = decoder.Decode(&varResourceState) + + if err != nil { + return err + } + + *o = ResourceState(varResourceState) + + return err +} + +type NullableResourceState struct { + value *ResourceState + isSet bool +} + +func (v NullableResourceState) Get() *ResourceState { + return v.value +} + +func (v *NullableResourceState) Set(val *ResourceState) { + v.value = val + v.isSet = true +} + +func (v NullableResourceState) IsSet() bool { + return v.isSet +} + +func (v *NullableResourceState) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableResourceState(val *ResourceState) *NullableResourceState { + return &NullableResourceState{value: val, isSet: true} +} + +func (v NullableResourceState) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableResourceState) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/pkg/apiclient/model_resource_type.go b/pkg/apiclient/model_resource_type.go new file mode 100644 index 0000000000..d9a330dd9d --- /dev/null +++ b/pkg/apiclient/model_resource_type.go @@ -0,0 +1,114 @@ +/* +Daytona Server API + +Daytona Server API + +API version: v0.0.0-dev +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package apiclient + +import ( + "encoding/json" + "fmt" +) + +// ResourceType the model 'ResourceType' +type ResourceType string + +// List of ResourceType +const ( + ResourceTypeWorkspace ResourceType = "workspace" + ResourceTypeTarget ResourceType = "target" + ResourceTypeBuild ResourceType = "build" + ResourceTypeRunner ResourceType = "runner" +) + +// All allowed values of ResourceType enum +var AllowedResourceTypeEnumValues = []ResourceType{ + "workspace", + "target", + "build", + "runner", +} + +func (v *ResourceType) UnmarshalJSON(src []byte) error { + var value string + err := json.Unmarshal(src, &value) + if err != nil { + return err + } + enumTypeValue := ResourceType(value) + for _, existing := range AllowedResourceTypeEnumValues { + if existing == enumTypeValue { + *v = enumTypeValue + return nil + } + } + + return fmt.Errorf("%+v is not a valid ResourceType", value) +} + +// NewResourceTypeFromValue returns a pointer to a valid ResourceType +// for the value passed as argument, or an error if the value passed is not allowed by the enum +func NewResourceTypeFromValue(v string) (*ResourceType, error) { + ev := ResourceType(v) + if ev.IsValid() { + return &ev, nil + } else { + return nil, fmt.Errorf("invalid value '%v' for ResourceType: valid values are %v", v, AllowedResourceTypeEnumValues) + } +} + +// IsValid return true if the value is valid for the enum, false otherwise +func (v ResourceType) IsValid() bool { + for _, existing := range AllowedResourceTypeEnumValues { + if existing == v { + return true + } + } + return false +} + +// Ptr returns reference to ResourceType value +func (v ResourceType) Ptr() *ResourceType { + return &v +} + +type NullableResourceType struct { + value *ResourceType + isSet bool +} + +func (v NullableResourceType) Get() *ResourceType { + return v.value +} + +func (v *NullableResourceType) Set(val *ResourceType) { + v.value = val + v.isSet = true +} + +func (v NullableResourceType) IsSet() bool { + return v.isSet +} + +func (v *NullableResourceType) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableResourceType(val *ResourceType) *NullableResourceType { + return &NullableResourceType{value: val, isSet: true} +} + +func (v NullableResourceType) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableResourceType) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/pkg/apiclient/model_runner_dto.go b/pkg/apiclient/model_runner_dto.go new file mode 100644 index 0000000000..97ec0212e9 --- /dev/null +++ b/pkg/apiclient/model_runner_dto.go @@ -0,0 +1,248 @@ +/* +Daytona Server API + +Daytona Server API + +API version: v0.0.0-dev +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package apiclient + +import ( + "bytes" + "encoding/json" + "fmt" +) + +// checks if the RunnerDTO type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &RunnerDTO{} + +// RunnerDTO struct for RunnerDTO +type RunnerDTO struct { + Id string `json:"id"` + Metadata *RunnerMetadata `json:"metadata,omitempty"` + Name string `json:"name"` + State ResourceState `json:"state"` +} + +type _RunnerDTO RunnerDTO + +// NewRunnerDTO instantiates a new RunnerDTO object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewRunnerDTO(id string, name string, state ResourceState) *RunnerDTO { + this := RunnerDTO{} + this.Id = id + this.Name = name + this.State = state + return &this +} + +// NewRunnerDTOWithDefaults instantiates a new RunnerDTO object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewRunnerDTOWithDefaults() *RunnerDTO { + this := RunnerDTO{} + return &this +} + +// GetId returns the Id field value +func (o *RunnerDTO) GetId() string { + if o == nil { + var ret string + return ret + } + + return o.Id +} + +// GetIdOk returns a tuple with the Id field value +// and a boolean to check if the value has been set. +func (o *RunnerDTO) GetIdOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Id, true +} + +// SetId sets field value +func (o *RunnerDTO) SetId(v string) { + o.Id = v +} + +// GetMetadata returns the Metadata field value if set, zero value otherwise. +func (o *RunnerDTO) GetMetadata() RunnerMetadata { + if o == nil || IsNil(o.Metadata) { + var ret RunnerMetadata + return ret + } + return *o.Metadata +} + +// GetMetadataOk returns a tuple with the Metadata field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *RunnerDTO) GetMetadataOk() (*RunnerMetadata, bool) { + if o == nil || IsNil(o.Metadata) { + return nil, false + } + return o.Metadata, true +} + +// HasMetadata returns a boolean if a field has been set. +func (o *RunnerDTO) HasMetadata() bool { + if o != nil && !IsNil(o.Metadata) { + return true + } + + return false +} + +// SetMetadata gets a reference to the given RunnerMetadata and assigns it to the Metadata field. +func (o *RunnerDTO) SetMetadata(v RunnerMetadata) { + o.Metadata = &v +} + +// GetName returns the Name field value +func (o *RunnerDTO) GetName() string { + if o == nil { + var ret string + return ret + } + + return o.Name +} + +// GetNameOk returns a tuple with the Name field value +// and a boolean to check if the value has been set. +func (o *RunnerDTO) GetNameOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Name, true +} + +// SetName sets field value +func (o *RunnerDTO) SetName(v string) { + o.Name = v +} + +// GetState returns the State field value +func (o *RunnerDTO) GetState() ResourceState { + if o == nil { + var ret ResourceState + return ret + } + + return o.State +} + +// GetStateOk returns a tuple with the State field value +// and a boolean to check if the value has been set. +func (o *RunnerDTO) GetStateOk() (*ResourceState, bool) { + if o == nil { + return nil, false + } + return &o.State, true +} + +// SetState sets field value +func (o *RunnerDTO) SetState(v ResourceState) { + o.State = v +} + +func (o RunnerDTO) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o RunnerDTO) ToMap() (map[string]interface{}, error) { + toSerialize := map[string]interface{}{} + toSerialize["id"] = o.Id + if !IsNil(o.Metadata) { + toSerialize["metadata"] = o.Metadata + } + toSerialize["name"] = o.Name + toSerialize["state"] = o.State + return toSerialize, nil +} + +func (o *RunnerDTO) UnmarshalJSON(data []byte) (err error) { + // This validates that all required properties are included in the JSON object + // by unmarshalling the object into a generic map with string keys and checking + // that every required field exists as a key in the generic map. + requiredProperties := []string{ + "id", + "name", + "state", + } + + allProperties := make(map[string]interface{}) + + err = json.Unmarshal(data, &allProperties) + + if err != nil { + return err + } + + for _, requiredProperty := range requiredProperties { + if _, exists := allProperties[requiredProperty]; !exists { + return fmt.Errorf("no value given for required property %v", requiredProperty) + } + } + + varRunnerDTO := _RunnerDTO{} + + decoder := json.NewDecoder(bytes.NewReader(data)) + decoder.DisallowUnknownFields() + err = decoder.Decode(&varRunnerDTO) + + if err != nil { + return err + } + + *o = RunnerDTO(varRunnerDTO) + + return err +} + +type NullableRunnerDTO struct { + value *RunnerDTO + isSet bool +} + +func (v NullableRunnerDTO) Get() *RunnerDTO { + return v.value +} + +func (v *NullableRunnerDTO) Set(val *RunnerDTO) { + v.value = val + v.isSet = true +} + +func (v NullableRunnerDTO) IsSet() bool { + return v.isSet +} + +func (v *NullableRunnerDTO) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableRunnerDTO(val *RunnerDTO) *NullableRunnerDTO { + return &NullableRunnerDTO{value: val, isSet: true} +} + +func (v NullableRunnerDTO) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableRunnerDTO) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/pkg/apiclient/model_runner_metadata.go b/pkg/apiclient/model_runner_metadata.go new file mode 100644 index 0000000000..d5d9ef3cbf --- /dev/null +++ b/pkg/apiclient/model_runner_metadata.go @@ -0,0 +1,276 @@ +/* +Daytona Server API + +Daytona Server API + +API version: v0.0.0-dev +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package apiclient + +import ( + "bytes" + "encoding/json" + "fmt" +) + +// checks if the RunnerMetadata type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &RunnerMetadata{} + +// RunnerMetadata struct for RunnerMetadata +type RunnerMetadata struct { + Providers []ProviderInfo `json:"providers"` + RunnerId string `json:"runnerId"` + RunningJobs *int32 `json:"runningJobs,omitempty"` + UpdatedAt string `json:"updatedAt"` + Uptime int32 `json:"uptime"` +} + +type _RunnerMetadata RunnerMetadata + +// NewRunnerMetadata instantiates a new RunnerMetadata object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewRunnerMetadata(providers []ProviderInfo, runnerId string, updatedAt string, uptime int32) *RunnerMetadata { + this := RunnerMetadata{} + this.Providers = providers + this.RunnerId = runnerId + this.UpdatedAt = updatedAt + this.Uptime = uptime + return &this +} + +// NewRunnerMetadataWithDefaults instantiates a new RunnerMetadata object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewRunnerMetadataWithDefaults() *RunnerMetadata { + this := RunnerMetadata{} + return &this +} + +// GetProviders returns the Providers field value +func (o *RunnerMetadata) GetProviders() []ProviderInfo { + if o == nil { + var ret []ProviderInfo + return ret + } + + return o.Providers +} + +// GetProvidersOk returns a tuple with the Providers field value +// and a boolean to check if the value has been set. +func (o *RunnerMetadata) GetProvidersOk() ([]ProviderInfo, bool) { + if o == nil { + return nil, false + } + return o.Providers, true +} + +// SetProviders sets field value +func (o *RunnerMetadata) SetProviders(v []ProviderInfo) { + o.Providers = v +} + +// GetRunnerId returns the RunnerId field value +func (o *RunnerMetadata) GetRunnerId() string { + if o == nil { + var ret string + return ret + } + + return o.RunnerId +} + +// GetRunnerIdOk returns a tuple with the RunnerId field value +// and a boolean to check if the value has been set. +func (o *RunnerMetadata) GetRunnerIdOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.RunnerId, true +} + +// SetRunnerId sets field value +func (o *RunnerMetadata) SetRunnerId(v string) { + o.RunnerId = v +} + +// GetRunningJobs returns the RunningJobs field value if set, zero value otherwise. +func (o *RunnerMetadata) GetRunningJobs() int32 { + if o == nil || IsNil(o.RunningJobs) { + var ret int32 + return ret + } + return *o.RunningJobs +} + +// GetRunningJobsOk returns a tuple with the RunningJobs field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *RunnerMetadata) GetRunningJobsOk() (*int32, bool) { + if o == nil || IsNil(o.RunningJobs) { + return nil, false + } + return o.RunningJobs, true +} + +// HasRunningJobs returns a boolean if a field has been set. +func (o *RunnerMetadata) HasRunningJobs() bool { + if o != nil && !IsNil(o.RunningJobs) { + return true + } + + return false +} + +// SetRunningJobs gets a reference to the given int32 and assigns it to the RunningJobs field. +func (o *RunnerMetadata) SetRunningJobs(v int32) { + o.RunningJobs = &v +} + +// GetUpdatedAt returns the UpdatedAt field value +func (o *RunnerMetadata) GetUpdatedAt() string { + if o == nil { + var ret string + return ret + } + + return o.UpdatedAt +} + +// GetUpdatedAtOk returns a tuple with the UpdatedAt field value +// and a boolean to check if the value has been set. +func (o *RunnerMetadata) GetUpdatedAtOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.UpdatedAt, true +} + +// SetUpdatedAt sets field value +func (o *RunnerMetadata) SetUpdatedAt(v string) { + o.UpdatedAt = v +} + +// GetUptime returns the Uptime field value +func (o *RunnerMetadata) GetUptime() int32 { + if o == nil { + var ret int32 + return ret + } + + return o.Uptime +} + +// GetUptimeOk returns a tuple with the Uptime field value +// and a boolean to check if the value has been set. +func (o *RunnerMetadata) GetUptimeOk() (*int32, bool) { + if o == nil { + return nil, false + } + return &o.Uptime, true +} + +// SetUptime sets field value +func (o *RunnerMetadata) SetUptime(v int32) { + o.Uptime = v +} + +func (o RunnerMetadata) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o RunnerMetadata) ToMap() (map[string]interface{}, error) { + toSerialize := map[string]interface{}{} + toSerialize["providers"] = o.Providers + toSerialize["runnerId"] = o.RunnerId + if !IsNil(o.RunningJobs) { + toSerialize["runningJobs"] = o.RunningJobs + } + toSerialize["updatedAt"] = o.UpdatedAt + toSerialize["uptime"] = o.Uptime + return toSerialize, nil +} + +func (o *RunnerMetadata) UnmarshalJSON(data []byte) (err error) { + // This validates that all required properties are included in the JSON object + // by unmarshalling the object into a generic map with string keys and checking + // that every required field exists as a key in the generic map. + requiredProperties := []string{ + "providers", + "runnerId", + "updatedAt", + "uptime", + } + + allProperties := make(map[string]interface{}) + + err = json.Unmarshal(data, &allProperties) + + if err != nil { + return err + } + + for _, requiredProperty := range requiredProperties { + if _, exists := allProperties[requiredProperty]; !exists { + return fmt.Errorf("no value given for required property %v", requiredProperty) + } + } + + varRunnerMetadata := _RunnerMetadata{} + + decoder := json.NewDecoder(bytes.NewReader(data)) + decoder.DisallowUnknownFields() + err = decoder.Decode(&varRunnerMetadata) + + if err != nil { + return err + } + + *o = RunnerMetadata(varRunnerMetadata) + + return err +} + +type NullableRunnerMetadata struct { + value *RunnerMetadata + isSet bool +} + +func (v NullableRunnerMetadata) Get() *RunnerMetadata { + return v.value +} + +func (v *NullableRunnerMetadata) Set(val *RunnerMetadata) { + v.value = val + v.isSet = true +} + +func (v NullableRunnerMetadata) IsSet() bool { + return v.isSet +} + +func (v *NullableRunnerMetadata) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableRunnerMetadata(val *RunnerMetadata) *NullableRunnerMetadata { + return &NullableRunnerMetadata{value: val, isSet: true} +} + +func (v NullableRunnerMetadata) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableRunnerMetadata) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/pkg/apiclient/model_server_config.go b/pkg/apiclient/model_server_config.go index 1e6843cd3d..a0104dd64c 100644 --- a/pkg/apiclient/model_server_config.go +++ b/pkg/apiclient/model_server_config.go @@ -26,15 +26,15 @@ type ServerConfig struct { BuildImageNamespace *string `json:"buildImageNamespace,omitempty"` BuilderImage string `json:"builderImage"` BuilderRegistryServer string `json:"builderRegistryServer"` - DefaultProjectImage string `json:"defaultProjectImage"` - DefaultProjectUser string `json:"defaultProjectUser"` + DefaultWorkspaceImage string `json:"defaultWorkspaceImage"` + DefaultWorkspaceUser string `json:"defaultWorkspaceUser"` Frps *FRPSConfig `json:"frps,omitempty"` HeadscalePort int32 `json:"headscalePort"` Id string `json:"id"` LocalBuilderRegistryImage string `json:"localBuilderRegistryImage"` LocalBuilderRegistryPort int32 `json:"localBuilderRegistryPort"` + LocalRunnerDisabled *bool `json:"localRunnerDisabled,omitempty"` LogFile LogFileConfig `json:"logFile"` - ProvidersDir string `json:"providersDir"` RegistryUrl string `json:"registryUrl"` SamplesIndexUrl *string `json:"samplesIndexUrl,omitempty"` ServerDownloadUrl string `json:"serverDownloadUrl"` @@ -46,20 +46,19 @@ type _ServerConfig ServerConfig // This constructor will assign default values to properties that have it defined, // and makes sure properties required by API are set, but the set of arguments // will change when the set of required properties is changed -func NewServerConfig(apiPort int32, binariesPath string, builderImage string, builderRegistryServer string, defaultProjectImage string, defaultProjectUser string, headscalePort int32, id string, localBuilderRegistryImage string, localBuilderRegistryPort int32, logFile LogFileConfig, providersDir string, registryUrl string, serverDownloadUrl string) *ServerConfig { +func NewServerConfig(apiPort int32, binariesPath string, builderImage string, builderRegistryServer string, defaultWorkspaceImage string, defaultWorkspaceUser string, headscalePort int32, id string, localBuilderRegistryImage string, localBuilderRegistryPort int32, logFile LogFileConfig, registryUrl string, serverDownloadUrl string) *ServerConfig { this := ServerConfig{} this.ApiPort = apiPort this.BinariesPath = binariesPath this.BuilderImage = builderImage this.BuilderRegistryServer = builderRegistryServer - this.DefaultProjectImage = defaultProjectImage - this.DefaultProjectUser = defaultProjectUser + this.DefaultWorkspaceImage = defaultWorkspaceImage + this.DefaultWorkspaceUser = defaultWorkspaceUser this.HeadscalePort = headscalePort this.Id = id this.LocalBuilderRegistryImage = localBuilderRegistryImage this.LocalBuilderRegistryPort = localBuilderRegistryPort this.LogFile = logFile - this.ProvidersDir = providersDir this.RegistryUrl = registryUrl this.ServerDownloadUrl = serverDownloadUrl return &this @@ -201,52 +200,52 @@ func (o *ServerConfig) SetBuilderRegistryServer(v string) { o.BuilderRegistryServer = v } -// GetDefaultProjectImage returns the DefaultProjectImage field value -func (o *ServerConfig) GetDefaultProjectImage() string { +// GetDefaultWorkspaceImage returns the DefaultWorkspaceImage field value +func (o *ServerConfig) GetDefaultWorkspaceImage() string { if o == nil { var ret string return ret } - return o.DefaultProjectImage + return o.DefaultWorkspaceImage } -// GetDefaultProjectImageOk returns a tuple with the DefaultProjectImage field value +// GetDefaultWorkspaceImageOk returns a tuple with the DefaultWorkspaceImage field value // and a boolean to check if the value has been set. -func (o *ServerConfig) GetDefaultProjectImageOk() (*string, bool) { +func (o *ServerConfig) GetDefaultWorkspaceImageOk() (*string, bool) { if o == nil { return nil, false } - return &o.DefaultProjectImage, true + return &o.DefaultWorkspaceImage, true } -// SetDefaultProjectImage sets field value -func (o *ServerConfig) SetDefaultProjectImage(v string) { - o.DefaultProjectImage = v +// SetDefaultWorkspaceImage sets field value +func (o *ServerConfig) SetDefaultWorkspaceImage(v string) { + o.DefaultWorkspaceImage = v } -// GetDefaultProjectUser returns the DefaultProjectUser field value -func (o *ServerConfig) GetDefaultProjectUser() string { +// GetDefaultWorkspaceUser returns the DefaultWorkspaceUser field value +func (o *ServerConfig) GetDefaultWorkspaceUser() string { if o == nil { var ret string return ret } - return o.DefaultProjectUser + return o.DefaultWorkspaceUser } -// GetDefaultProjectUserOk returns a tuple with the DefaultProjectUser field value +// GetDefaultWorkspaceUserOk returns a tuple with the DefaultWorkspaceUser field value // and a boolean to check if the value has been set. -func (o *ServerConfig) GetDefaultProjectUserOk() (*string, bool) { +func (o *ServerConfig) GetDefaultWorkspaceUserOk() (*string, bool) { if o == nil { return nil, false } - return &o.DefaultProjectUser, true + return &o.DefaultWorkspaceUser, true } -// SetDefaultProjectUser sets field value -func (o *ServerConfig) SetDefaultProjectUser(v string) { - o.DefaultProjectUser = v +// SetDefaultWorkspaceUser sets field value +func (o *ServerConfig) SetDefaultWorkspaceUser(v string) { + o.DefaultWorkspaceUser = v } // GetFrps returns the Frps field value if set, zero value otherwise. @@ -377,52 +376,60 @@ func (o *ServerConfig) SetLocalBuilderRegistryPort(v int32) { o.LocalBuilderRegistryPort = v } -// GetLogFile returns the LogFile field value -func (o *ServerConfig) GetLogFile() LogFileConfig { - if o == nil { - var ret LogFileConfig +// GetLocalRunnerDisabled returns the LocalRunnerDisabled field value if set, zero value otherwise. +func (o *ServerConfig) GetLocalRunnerDisabled() bool { + if o == nil || IsNil(o.LocalRunnerDisabled) { + var ret bool return ret } - - return o.LogFile + return *o.LocalRunnerDisabled } -// GetLogFileOk returns a tuple with the LogFile field value +// GetLocalRunnerDisabledOk returns a tuple with the LocalRunnerDisabled field value if set, nil otherwise // and a boolean to check if the value has been set. -func (o *ServerConfig) GetLogFileOk() (*LogFileConfig, bool) { - if o == nil { +func (o *ServerConfig) GetLocalRunnerDisabledOk() (*bool, bool) { + if o == nil || IsNil(o.LocalRunnerDisabled) { return nil, false } - return &o.LogFile, true + return o.LocalRunnerDisabled, true } -// SetLogFile sets field value -func (o *ServerConfig) SetLogFile(v LogFileConfig) { - o.LogFile = v +// HasLocalRunnerDisabled returns a boolean if a field has been set. +func (o *ServerConfig) HasLocalRunnerDisabled() bool { + if o != nil && !IsNil(o.LocalRunnerDisabled) { + return true + } + + return false +} + +// SetLocalRunnerDisabled gets a reference to the given bool and assigns it to the LocalRunnerDisabled field. +func (o *ServerConfig) SetLocalRunnerDisabled(v bool) { + o.LocalRunnerDisabled = &v } -// GetProvidersDir returns the ProvidersDir field value -func (o *ServerConfig) GetProvidersDir() string { +// GetLogFile returns the LogFile field value +func (o *ServerConfig) GetLogFile() LogFileConfig { if o == nil { - var ret string + var ret LogFileConfig return ret } - return o.ProvidersDir + return o.LogFile } -// GetProvidersDirOk returns a tuple with the ProvidersDir field value +// GetLogFileOk returns a tuple with the LogFile field value // and a boolean to check if the value has been set. -func (o *ServerConfig) GetProvidersDirOk() (*string, bool) { +func (o *ServerConfig) GetLogFileOk() (*LogFileConfig, bool) { if o == nil { return nil, false } - return &o.ProvidersDir, true + return &o.LogFile, true } -// SetProvidersDir sets field value -func (o *ServerConfig) SetProvidersDir(v string) { - o.ProvidersDir = v +// SetLogFile sets field value +func (o *ServerConfig) SetLogFile(v LogFileConfig) { + o.LogFile = v } // GetRegistryUrl returns the RegistryUrl field value @@ -522,8 +529,8 @@ func (o ServerConfig) ToMap() (map[string]interface{}, error) { } toSerialize["builderImage"] = o.BuilderImage toSerialize["builderRegistryServer"] = o.BuilderRegistryServer - toSerialize["defaultProjectImage"] = o.DefaultProjectImage - toSerialize["defaultProjectUser"] = o.DefaultProjectUser + toSerialize["defaultWorkspaceImage"] = o.DefaultWorkspaceImage + toSerialize["defaultWorkspaceUser"] = o.DefaultWorkspaceUser if !IsNil(o.Frps) { toSerialize["frps"] = o.Frps } @@ -531,8 +538,10 @@ func (o ServerConfig) ToMap() (map[string]interface{}, error) { toSerialize["id"] = o.Id toSerialize["localBuilderRegistryImage"] = o.LocalBuilderRegistryImage toSerialize["localBuilderRegistryPort"] = o.LocalBuilderRegistryPort + if !IsNil(o.LocalRunnerDisabled) { + toSerialize["localRunnerDisabled"] = o.LocalRunnerDisabled + } toSerialize["logFile"] = o.LogFile - toSerialize["providersDir"] = o.ProvidersDir toSerialize["registryUrl"] = o.RegistryUrl if !IsNil(o.SamplesIndexUrl) { toSerialize["samplesIndexUrl"] = o.SamplesIndexUrl @@ -550,14 +559,13 @@ func (o *ServerConfig) UnmarshalJSON(data []byte) (err error) { "binariesPath", "builderImage", "builderRegistryServer", - "defaultProjectImage", - "defaultProjectUser", + "defaultWorkspaceImage", + "defaultWorkspaceUser", "headscalePort", "id", "localBuilderRegistryImage", "localBuilderRegistryPort", "logFile", - "providersDir", "registryUrl", "serverDownloadUrl", } diff --git a/pkg/apiclient/model_target.go b/pkg/apiclient/model_target.go new file mode 100644 index 0000000000..647ba596ab --- /dev/null +++ b/pkg/apiclient/model_target.go @@ -0,0 +1,468 @@ +/* +Daytona Server API + +Daytona Server API + +API version: v0.0.0-dev +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package apiclient + +import ( + "bytes" + "encoding/json" + "fmt" +) + +// checks if the Target type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &Target{} + +// Target struct for Target +type Target struct { + Default bool `json:"default"` + EnvVars map[string]string `json:"envVars"` + Id string `json:"id"` + LastJob *Job `json:"lastJob,omitempty"` + LastJobId *string `json:"lastJobId,omitempty"` + Metadata *TargetMetadata `json:"metadata,omitempty"` + Name string `json:"name"` + ProviderMetadata *string `json:"providerMetadata,omitempty"` + TargetConfig TargetConfig `json:"targetConfig"` + TargetConfigId string `json:"targetConfigId"` + Workspaces []Workspace `json:"workspaces"` +} + +type _Target Target + +// NewTarget instantiates a new Target object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewTarget(default_ bool, envVars map[string]string, id string, name string, targetConfig TargetConfig, targetConfigId string, workspaces []Workspace) *Target { + this := Target{} + this.Default = default_ + this.EnvVars = envVars + this.Id = id + this.Name = name + this.TargetConfig = targetConfig + this.TargetConfigId = targetConfigId + this.Workspaces = workspaces + return &this +} + +// NewTargetWithDefaults instantiates a new Target object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewTargetWithDefaults() *Target { + this := Target{} + return &this +} + +// GetDefault returns the Default field value +func (o *Target) GetDefault() bool { + if o == nil { + var ret bool + return ret + } + + return o.Default +} + +// GetDefaultOk returns a tuple with the Default field value +// and a boolean to check if the value has been set. +func (o *Target) GetDefaultOk() (*bool, bool) { + if o == nil { + return nil, false + } + return &o.Default, true +} + +// SetDefault sets field value +func (o *Target) SetDefault(v bool) { + o.Default = v +} + +// GetEnvVars returns the EnvVars field value +func (o *Target) GetEnvVars() map[string]string { + if o == nil { + var ret map[string]string + return ret + } + + return o.EnvVars +} + +// GetEnvVarsOk returns a tuple with the EnvVars field value +// and a boolean to check if the value has been set. +func (o *Target) GetEnvVarsOk() (*map[string]string, bool) { + if o == nil { + return nil, false + } + return &o.EnvVars, true +} + +// SetEnvVars sets field value +func (o *Target) SetEnvVars(v map[string]string) { + o.EnvVars = v +} + +// GetId returns the Id field value +func (o *Target) GetId() string { + if o == nil { + var ret string + return ret + } + + return o.Id +} + +// GetIdOk returns a tuple with the Id field value +// and a boolean to check if the value has been set. +func (o *Target) GetIdOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Id, true +} + +// SetId sets field value +func (o *Target) SetId(v string) { + o.Id = v +} + +// GetLastJob returns the LastJob field value if set, zero value otherwise. +func (o *Target) GetLastJob() Job { + if o == nil || IsNil(o.LastJob) { + var ret Job + return ret + } + return *o.LastJob +} + +// GetLastJobOk returns a tuple with the LastJob field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *Target) GetLastJobOk() (*Job, bool) { + if o == nil || IsNil(o.LastJob) { + return nil, false + } + return o.LastJob, true +} + +// HasLastJob returns a boolean if a field has been set. +func (o *Target) HasLastJob() bool { + if o != nil && !IsNil(o.LastJob) { + return true + } + + return false +} + +// SetLastJob gets a reference to the given Job and assigns it to the LastJob field. +func (o *Target) SetLastJob(v Job) { + o.LastJob = &v +} + +// GetLastJobId returns the LastJobId field value if set, zero value otherwise. +func (o *Target) GetLastJobId() string { + if o == nil || IsNil(o.LastJobId) { + var ret string + return ret + } + return *o.LastJobId +} + +// GetLastJobIdOk returns a tuple with the LastJobId field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *Target) GetLastJobIdOk() (*string, bool) { + if o == nil || IsNil(o.LastJobId) { + return nil, false + } + return o.LastJobId, true +} + +// HasLastJobId returns a boolean if a field has been set. +func (o *Target) HasLastJobId() bool { + if o != nil && !IsNil(o.LastJobId) { + return true + } + + return false +} + +// SetLastJobId gets a reference to the given string and assigns it to the LastJobId field. +func (o *Target) SetLastJobId(v string) { + o.LastJobId = &v +} + +// GetMetadata returns the Metadata field value if set, zero value otherwise. +func (o *Target) GetMetadata() TargetMetadata { + if o == nil || IsNil(o.Metadata) { + var ret TargetMetadata + return ret + } + return *o.Metadata +} + +// GetMetadataOk returns a tuple with the Metadata field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *Target) GetMetadataOk() (*TargetMetadata, bool) { + if o == nil || IsNil(o.Metadata) { + return nil, false + } + return o.Metadata, true +} + +// HasMetadata returns a boolean if a field has been set. +func (o *Target) HasMetadata() bool { + if o != nil && !IsNil(o.Metadata) { + return true + } + + return false +} + +// SetMetadata gets a reference to the given TargetMetadata and assigns it to the Metadata field. +func (o *Target) SetMetadata(v TargetMetadata) { + o.Metadata = &v +} + +// GetName returns the Name field value +func (o *Target) GetName() string { + if o == nil { + var ret string + return ret + } + + return o.Name +} + +// GetNameOk returns a tuple with the Name field value +// and a boolean to check if the value has been set. +func (o *Target) GetNameOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Name, true +} + +// SetName sets field value +func (o *Target) SetName(v string) { + o.Name = v +} + +// GetProviderMetadata returns the ProviderMetadata field value if set, zero value otherwise. +func (o *Target) GetProviderMetadata() string { + if o == nil || IsNil(o.ProviderMetadata) { + var ret string + return ret + } + return *o.ProviderMetadata +} + +// GetProviderMetadataOk returns a tuple with the ProviderMetadata field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *Target) GetProviderMetadataOk() (*string, bool) { + if o == nil || IsNil(o.ProviderMetadata) { + return nil, false + } + return o.ProviderMetadata, true +} + +// HasProviderMetadata returns a boolean if a field has been set. +func (o *Target) HasProviderMetadata() bool { + if o != nil && !IsNil(o.ProviderMetadata) { + return true + } + + return false +} + +// SetProviderMetadata gets a reference to the given string and assigns it to the ProviderMetadata field. +func (o *Target) SetProviderMetadata(v string) { + o.ProviderMetadata = &v +} + +// GetTargetConfig returns the TargetConfig field value +func (o *Target) GetTargetConfig() TargetConfig { + if o == nil { + var ret TargetConfig + return ret + } + + return o.TargetConfig +} + +// GetTargetConfigOk returns a tuple with the TargetConfig field value +// and a boolean to check if the value has been set. +func (o *Target) GetTargetConfigOk() (*TargetConfig, bool) { + if o == nil { + return nil, false + } + return &o.TargetConfig, true +} + +// SetTargetConfig sets field value +func (o *Target) SetTargetConfig(v TargetConfig) { + o.TargetConfig = v +} + +// GetTargetConfigId returns the TargetConfigId field value +func (o *Target) GetTargetConfigId() string { + if o == nil { + var ret string + return ret + } + + return o.TargetConfigId +} + +// GetTargetConfigIdOk returns a tuple with the TargetConfigId field value +// and a boolean to check if the value has been set. +func (o *Target) GetTargetConfigIdOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.TargetConfigId, true +} + +// SetTargetConfigId sets field value +func (o *Target) SetTargetConfigId(v string) { + o.TargetConfigId = v +} + +// GetWorkspaces returns the Workspaces field value +func (o *Target) GetWorkspaces() []Workspace { + if o == nil { + var ret []Workspace + return ret + } + + return o.Workspaces +} + +// GetWorkspacesOk returns a tuple with the Workspaces field value +// and a boolean to check if the value has been set. +func (o *Target) GetWorkspacesOk() ([]Workspace, bool) { + if o == nil { + return nil, false + } + return o.Workspaces, true +} + +// SetWorkspaces sets field value +func (o *Target) SetWorkspaces(v []Workspace) { + o.Workspaces = v +} + +func (o Target) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o Target) ToMap() (map[string]interface{}, error) { + toSerialize := map[string]interface{}{} + toSerialize["default"] = o.Default + toSerialize["envVars"] = o.EnvVars + toSerialize["id"] = o.Id + if !IsNil(o.LastJob) { + toSerialize["lastJob"] = o.LastJob + } + if !IsNil(o.LastJobId) { + toSerialize["lastJobId"] = o.LastJobId + } + if !IsNil(o.Metadata) { + toSerialize["metadata"] = o.Metadata + } + toSerialize["name"] = o.Name + if !IsNil(o.ProviderMetadata) { + toSerialize["providerMetadata"] = o.ProviderMetadata + } + toSerialize["targetConfig"] = o.TargetConfig + toSerialize["targetConfigId"] = o.TargetConfigId + toSerialize["workspaces"] = o.Workspaces + return toSerialize, nil +} + +func (o *Target) UnmarshalJSON(data []byte) (err error) { + // This validates that all required properties are included in the JSON object + // by unmarshalling the object into a generic map with string keys and checking + // that every required field exists as a key in the generic map. + requiredProperties := []string{ + "default", + "envVars", + "id", + "name", + "targetConfig", + "targetConfigId", + "workspaces", + } + + allProperties := make(map[string]interface{}) + + err = json.Unmarshal(data, &allProperties) + + if err != nil { + return err + } + + for _, requiredProperty := range requiredProperties { + if _, exists := allProperties[requiredProperty]; !exists { + return fmt.Errorf("no value given for required property %v", requiredProperty) + } + } + + varTarget := _Target{} + + decoder := json.NewDecoder(bytes.NewReader(data)) + decoder.DisallowUnknownFields() + err = decoder.Decode(&varTarget) + + if err != nil { + return err + } + + *o = Target(varTarget) + + return err +} + +type NullableTarget struct { + value *Target + isSet bool +} + +func (v NullableTarget) Get() *Target { + return v.value +} + +func (v *NullableTarget) Set(val *Target) { + v.value = val + v.isSet = true +} + +func (v NullableTarget) IsSet() bool { + return v.isSet +} + +func (v *NullableTarget) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableTarget(val *Target) *NullableTarget { + return &NullableTarget{value: val, isSet: true} +} + +func (v NullableTarget) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableTarget) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/pkg/apiclient/model_provider_target.go b/pkg/apiclient/model_target_config.go similarity index 52% rename from pkg/apiclient/model_provider_target.go rename to pkg/apiclient/model_target_config.go index 2d77e6a703..99c639126c 100644 --- a/pkg/apiclient/model_provider_target.go +++ b/pkg/apiclient/model_target_config.go @@ -16,67 +16,93 @@ import ( "fmt" ) -// checks if the ProviderTarget type satisfies the MappedNullable interface at compile time -var _ MappedNullable = &ProviderTarget{} - -// ProviderTarget struct for ProviderTarget -type ProviderTarget struct { - IsDefault bool `json:"isDefault"` - Name string `json:"name"` +// checks if the TargetConfig type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &TargetConfig{} + +// TargetConfig struct for TargetConfig +type TargetConfig struct { + Deleted bool `json:"deleted"` + Id string `json:"id"` + Name string `json:"name"` // JSON encoded map of options - Options string `json:"options"` - ProviderInfo ProviderProviderInfo `json:"providerInfo"` + Options string `json:"options"` + ProviderInfo ProviderInfo `json:"providerInfo"` } -type _ProviderTarget ProviderTarget +type _TargetConfig TargetConfig -// NewProviderTarget instantiates a new ProviderTarget object +// NewTargetConfig instantiates a new TargetConfig object // This constructor will assign default values to properties that have it defined, // and makes sure properties required by API are set, but the set of arguments // will change when the set of required properties is changed -func NewProviderTarget(isDefault bool, name string, options string, providerInfo ProviderProviderInfo) *ProviderTarget { - this := ProviderTarget{} - this.IsDefault = isDefault +func NewTargetConfig(deleted bool, id string, name string, options string, providerInfo ProviderInfo) *TargetConfig { + this := TargetConfig{} + this.Deleted = deleted + this.Id = id this.Name = name this.Options = options this.ProviderInfo = providerInfo return &this } -// NewProviderTargetWithDefaults instantiates a new ProviderTarget object +// NewTargetConfigWithDefaults instantiates a new TargetConfig object // This constructor will only assign default values to properties that have it defined, // but it doesn't guarantee that properties required by API are set -func NewProviderTargetWithDefaults() *ProviderTarget { - this := ProviderTarget{} +func NewTargetConfigWithDefaults() *TargetConfig { + this := TargetConfig{} return &this } -// GetIsDefault returns the IsDefault field value -func (o *ProviderTarget) GetIsDefault() bool { +// GetDeleted returns the Deleted field value +func (o *TargetConfig) GetDeleted() bool { if o == nil { var ret bool return ret } - return o.IsDefault + return o.Deleted +} + +// GetDeletedOk returns a tuple with the Deleted field value +// and a boolean to check if the value has been set. +func (o *TargetConfig) GetDeletedOk() (*bool, bool) { + if o == nil { + return nil, false + } + return &o.Deleted, true +} + +// SetDeleted sets field value +func (o *TargetConfig) SetDeleted(v bool) { + o.Deleted = v +} + +// GetId returns the Id field value +func (o *TargetConfig) GetId() string { + if o == nil { + var ret string + return ret + } + + return o.Id } -// GetIsDefaultOk returns a tuple with the IsDefault field value +// GetIdOk returns a tuple with the Id field value // and a boolean to check if the value has been set. -func (o *ProviderTarget) GetIsDefaultOk() (*bool, bool) { +func (o *TargetConfig) GetIdOk() (*string, bool) { if o == nil { return nil, false } - return &o.IsDefault, true + return &o.Id, true } -// SetIsDefault sets field value -func (o *ProviderTarget) SetIsDefault(v bool) { - o.IsDefault = v +// SetId sets field value +func (o *TargetConfig) SetId(v string) { + o.Id = v } // GetName returns the Name field value -func (o *ProviderTarget) GetName() string { +func (o *TargetConfig) GetName() string { if o == nil { var ret string return ret @@ -87,7 +113,7 @@ func (o *ProviderTarget) GetName() string { // GetNameOk returns a tuple with the Name field value // and a boolean to check if the value has been set. -func (o *ProviderTarget) GetNameOk() (*string, bool) { +func (o *TargetConfig) GetNameOk() (*string, bool) { if o == nil { return nil, false } @@ -95,12 +121,12 @@ func (o *ProviderTarget) GetNameOk() (*string, bool) { } // SetName sets field value -func (o *ProviderTarget) SetName(v string) { +func (o *TargetConfig) SetName(v string) { o.Name = v } // GetOptions returns the Options field value -func (o *ProviderTarget) GetOptions() string { +func (o *TargetConfig) GetOptions() string { if o == nil { var ret string return ret @@ -111,7 +137,7 @@ func (o *ProviderTarget) GetOptions() string { // GetOptionsOk returns a tuple with the Options field value // and a boolean to check if the value has been set. -func (o *ProviderTarget) GetOptionsOk() (*string, bool) { +func (o *TargetConfig) GetOptionsOk() (*string, bool) { if o == nil { return nil, false } @@ -119,14 +145,14 @@ func (o *ProviderTarget) GetOptionsOk() (*string, bool) { } // SetOptions sets field value -func (o *ProviderTarget) SetOptions(v string) { +func (o *TargetConfig) SetOptions(v string) { o.Options = v } // GetProviderInfo returns the ProviderInfo field value -func (o *ProviderTarget) GetProviderInfo() ProviderProviderInfo { +func (o *TargetConfig) GetProviderInfo() ProviderInfo { if o == nil { - var ret ProviderProviderInfo + var ret ProviderInfo return ret } @@ -135,7 +161,7 @@ func (o *ProviderTarget) GetProviderInfo() ProviderProviderInfo { // GetProviderInfoOk returns a tuple with the ProviderInfo field value // and a boolean to check if the value has been set. -func (o *ProviderTarget) GetProviderInfoOk() (*ProviderProviderInfo, bool) { +func (o *TargetConfig) GetProviderInfoOk() (*ProviderInfo, bool) { if o == nil { return nil, false } @@ -143,11 +169,11 @@ func (o *ProviderTarget) GetProviderInfoOk() (*ProviderProviderInfo, bool) { } // SetProviderInfo sets field value -func (o *ProviderTarget) SetProviderInfo(v ProviderProviderInfo) { +func (o *TargetConfig) SetProviderInfo(v ProviderInfo) { o.ProviderInfo = v } -func (o ProviderTarget) MarshalJSON() ([]byte, error) { +func (o TargetConfig) MarshalJSON() ([]byte, error) { toSerialize, err := o.ToMap() if err != nil { return []byte{}, err @@ -155,21 +181,23 @@ func (o ProviderTarget) MarshalJSON() ([]byte, error) { return json.Marshal(toSerialize) } -func (o ProviderTarget) ToMap() (map[string]interface{}, error) { +func (o TargetConfig) ToMap() (map[string]interface{}, error) { toSerialize := map[string]interface{}{} - toSerialize["isDefault"] = o.IsDefault + toSerialize["deleted"] = o.Deleted + toSerialize["id"] = o.Id toSerialize["name"] = o.Name toSerialize["options"] = o.Options toSerialize["providerInfo"] = o.ProviderInfo return toSerialize, nil } -func (o *ProviderTarget) UnmarshalJSON(data []byte) (err error) { +func (o *TargetConfig) UnmarshalJSON(data []byte) (err error) { // This validates that all required properties are included in the JSON object // by unmarshalling the object into a generic map with string keys and checking // that every required field exists as a key in the generic map. requiredProperties := []string{ - "isDefault", + "deleted", + "id", "name", "options", "providerInfo", @@ -189,53 +217,53 @@ func (o *ProviderTarget) UnmarshalJSON(data []byte) (err error) { } } - varProviderTarget := _ProviderTarget{} + varTargetConfig := _TargetConfig{} decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() - err = decoder.Decode(&varProviderTarget) + err = decoder.Decode(&varTargetConfig) if err != nil { return err } - *o = ProviderTarget(varProviderTarget) + *o = TargetConfig(varTargetConfig) return err } -type NullableProviderTarget struct { - value *ProviderTarget +type NullableTargetConfig struct { + value *TargetConfig isSet bool } -func (v NullableProviderTarget) Get() *ProviderTarget { +func (v NullableTargetConfig) Get() *TargetConfig { return v.value } -func (v *NullableProviderTarget) Set(val *ProviderTarget) { +func (v *NullableTargetConfig) Set(val *TargetConfig) { v.value = val v.isSet = true } -func (v NullableProviderTarget) IsSet() bool { +func (v NullableTargetConfig) IsSet() bool { return v.isSet } -func (v *NullableProviderTarget) Unset() { +func (v *NullableTargetConfig) Unset() { v.value = nil v.isSet = false } -func NewNullableProviderTarget(val *ProviderTarget) *NullableProviderTarget { - return &NullableProviderTarget{value: val, isSet: true} +func NewNullableTargetConfig(val *TargetConfig) *NullableTargetConfig { + return &NullableTargetConfig{value: val, isSet: true} } -func (v NullableProviderTarget) MarshalJSON() ([]byte, error) { +func (v NullableTargetConfig) MarshalJSON() ([]byte, error) { return json.Marshal(v.value) } -func (v *NullableProviderTarget) UnmarshalJSON(src []byte) error { +func (v *NullableTargetConfig) UnmarshalJSON(src []byte) error { v.isSet = true return json.Unmarshal(src, &v.value) } diff --git a/pkg/apiclient/model_provider_provider_target_property.go b/pkg/apiclient/model_target_config_property.go similarity index 61% rename from pkg/apiclient/model_provider_provider_target_property.go rename to pkg/apiclient/model_target_config_property.go index be99c70e05..a341a887bb 100644 --- a/pkg/apiclient/model_provider_provider_target_property.go +++ b/pkg/apiclient/model_target_config_property.go @@ -14,44 +14,44 @@ import ( "encoding/json" ) -// checks if the ProviderProviderTargetProperty type satisfies the MappedNullable interface at compile time -var _ MappedNullable = &ProviderProviderTargetProperty{} +// checks if the TargetConfigProperty type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &TargetConfigProperty{} -// ProviderProviderTargetProperty struct for ProviderProviderTargetProperty -type ProviderProviderTargetProperty struct { +// TargetConfigProperty struct for TargetConfigProperty +type TargetConfigProperty struct { // DefaultValue is converted into the appropriate type based on the Type If the property is a FilePath, the DefaultValue is a path to a directory DefaultValue *string `json:"defaultValue,omitempty"` // Brief description of the property Description *string `json:"description,omitempty"` - // A regex string matched with the name of the target to determine if the property should be disabled If the regex matches the target name, the property will be disabled E.g. \"^local$\" will disable the property for the local target + // A regex string matched with the name of the target config to determine if the property should be disabled If the regex matches the target config name, the property will be disabled E.g. \"^local$\" will disable the property for the local target DisabledPredicate *string `json:"disabledPredicate,omitempty"` InputMasked *bool `json:"inputMasked,omitempty"` - // Options is only used if the Type is ProviderTargetPropertyTypeOption + // Options is only used if the Type is TargetConfigPropertyTypeOption Options []string `json:"options,omitempty"` // Suggestions is an optional list of auto-complete values to assist the user while filling the field - Suggestions []string `json:"suggestions,omitempty"` - Type *ProviderProviderTargetPropertyType `json:"type,omitempty"` + Suggestions []string `json:"suggestions,omitempty"` + Type *ModelsTargetConfigPropertyType `json:"type,omitempty"` } -// NewProviderProviderTargetProperty instantiates a new ProviderProviderTargetProperty object +// NewTargetConfigProperty instantiates a new TargetConfigProperty object // This constructor will assign default values to properties that have it defined, // and makes sure properties required by API are set, but the set of arguments // will change when the set of required properties is changed -func NewProviderProviderTargetProperty() *ProviderProviderTargetProperty { - this := ProviderProviderTargetProperty{} +func NewTargetConfigProperty() *TargetConfigProperty { + this := TargetConfigProperty{} return &this } -// NewProviderProviderTargetPropertyWithDefaults instantiates a new ProviderProviderTargetProperty object +// NewTargetConfigPropertyWithDefaults instantiates a new TargetConfigProperty object // This constructor will only assign default values to properties that have it defined, // but it doesn't guarantee that properties required by API are set -func NewProviderProviderTargetPropertyWithDefaults() *ProviderProviderTargetProperty { - this := ProviderProviderTargetProperty{} +func NewTargetConfigPropertyWithDefaults() *TargetConfigProperty { + this := TargetConfigProperty{} return &this } // GetDefaultValue returns the DefaultValue field value if set, zero value otherwise. -func (o *ProviderProviderTargetProperty) GetDefaultValue() string { +func (o *TargetConfigProperty) GetDefaultValue() string { if o == nil || IsNil(o.DefaultValue) { var ret string return ret @@ -61,7 +61,7 @@ func (o *ProviderProviderTargetProperty) GetDefaultValue() string { // GetDefaultValueOk returns a tuple with the DefaultValue field value if set, nil otherwise // and a boolean to check if the value has been set. -func (o *ProviderProviderTargetProperty) GetDefaultValueOk() (*string, bool) { +func (o *TargetConfigProperty) GetDefaultValueOk() (*string, bool) { if o == nil || IsNil(o.DefaultValue) { return nil, false } @@ -69,7 +69,7 @@ func (o *ProviderProviderTargetProperty) GetDefaultValueOk() (*string, bool) { } // HasDefaultValue returns a boolean if a field has been set. -func (o *ProviderProviderTargetProperty) HasDefaultValue() bool { +func (o *TargetConfigProperty) HasDefaultValue() bool { if o != nil && !IsNil(o.DefaultValue) { return true } @@ -78,12 +78,12 @@ func (o *ProviderProviderTargetProperty) HasDefaultValue() bool { } // SetDefaultValue gets a reference to the given string and assigns it to the DefaultValue field. -func (o *ProviderProviderTargetProperty) SetDefaultValue(v string) { +func (o *TargetConfigProperty) SetDefaultValue(v string) { o.DefaultValue = &v } // GetDescription returns the Description field value if set, zero value otherwise. -func (o *ProviderProviderTargetProperty) GetDescription() string { +func (o *TargetConfigProperty) GetDescription() string { if o == nil || IsNil(o.Description) { var ret string return ret @@ -93,7 +93,7 @@ func (o *ProviderProviderTargetProperty) GetDescription() string { // GetDescriptionOk returns a tuple with the Description field value if set, nil otherwise // and a boolean to check if the value has been set. -func (o *ProviderProviderTargetProperty) GetDescriptionOk() (*string, bool) { +func (o *TargetConfigProperty) GetDescriptionOk() (*string, bool) { if o == nil || IsNil(o.Description) { return nil, false } @@ -101,7 +101,7 @@ func (o *ProviderProviderTargetProperty) GetDescriptionOk() (*string, bool) { } // HasDescription returns a boolean if a field has been set. -func (o *ProviderProviderTargetProperty) HasDescription() bool { +func (o *TargetConfigProperty) HasDescription() bool { if o != nil && !IsNil(o.Description) { return true } @@ -110,12 +110,12 @@ func (o *ProviderProviderTargetProperty) HasDescription() bool { } // SetDescription gets a reference to the given string and assigns it to the Description field. -func (o *ProviderProviderTargetProperty) SetDescription(v string) { +func (o *TargetConfigProperty) SetDescription(v string) { o.Description = &v } // GetDisabledPredicate returns the DisabledPredicate field value if set, zero value otherwise. -func (o *ProviderProviderTargetProperty) GetDisabledPredicate() string { +func (o *TargetConfigProperty) GetDisabledPredicate() string { if o == nil || IsNil(o.DisabledPredicate) { var ret string return ret @@ -125,7 +125,7 @@ func (o *ProviderProviderTargetProperty) GetDisabledPredicate() string { // GetDisabledPredicateOk returns a tuple with the DisabledPredicate field value if set, nil otherwise // and a boolean to check if the value has been set. -func (o *ProviderProviderTargetProperty) GetDisabledPredicateOk() (*string, bool) { +func (o *TargetConfigProperty) GetDisabledPredicateOk() (*string, bool) { if o == nil || IsNil(o.DisabledPredicate) { return nil, false } @@ -133,7 +133,7 @@ func (o *ProviderProviderTargetProperty) GetDisabledPredicateOk() (*string, bool } // HasDisabledPredicate returns a boolean if a field has been set. -func (o *ProviderProviderTargetProperty) HasDisabledPredicate() bool { +func (o *TargetConfigProperty) HasDisabledPredicate() bool { if o != nil && !IsNil(o.DisabledPredicate) { return true } @@ -142,12 +142,12 @@ func (o *ProviderProviderTargetProperty) HasDisabledPredicate() bool { } // SetDisabledPredicate gets a reference to the given string and assigns it to the DisabledPredicate field. -func (o *ProviderProviderTargetProperty) SetDisabledPredicate(v string) { +func (o *TargetConfigProperty) SetDisabledPredicate(v string) { o.DisabledPredicate = &v } // GetInputMasked returns the InputMasked field value if set, zero value otherwise. -func (o *ProviderProviderTargetProperty) GetInputMasked() bool { +func (o *TargetConfigProperty) GetInputMasked() bool { if o == nil || IsNil(o.InputMasked) { var ret bool return ret @@ -157,7 +157,7 @@ func (o *ProviderProviderTargetProperty) GetInputMasked() bool { // GetInputMaskedOk returns a tuple with the InputMasked field value if set, nil otherwise // and a boolean to check if the value has been set. -func (o *ProviderProviderTargetProperty) GetInputMaskedOk() (*bool, bool) { +func (o *TargetConfigProperty) GetInputMaskedOk() (*bool, bool) { if o == nil || IsNil(o.InputMasked) { return nil, false } @@ -165,7 +165,7 @@ func (o *ProviderProviderTargetProperty) GetInputMaskedOk() (*bool, bool) { } // HasInputMasked returns a boolean if a field has been set. -func (o *ProviderProviderTargetProperty) HasInputMasked() bool { +func (o *TargetConfigProperty) HasInputMasked() bool { if o != nil && !IsNil(o.InputMasked) { return true } @@ -174,12 +174,12 @@ func (o *ProviderProviderTargetProperty) HasInputMasked() bool { } // SetInputMasked gets a reference to the given bool and assigns it to the InputMasked field. -func (o *ProviderProviderTargetProperty) SetInputMasked(v bool) { +func (o *TargetConfigProperty) SetInputMasked(v bool) { o.InputMasked = &v } // GetOptions returns the Options field value if set, zero value otherwise. -func (o *ProviderProviderTargetProperty) GetOptions() []string { +func (o *TargetConfigProperty) GetOptions() []string { if o == nil || IsNil(o.Options) { var ret []string return ret @@ -189,7 +189,7 @@ func (o *ProviderProviderTargetProperty) GetOptions() []string { // GetOptionsOk returns a tuple with the Options field value if set, nil otherwise // and a boolean to check if the value has been set. -func (o *ProviderProviderTargetProperty) GetOptionsOk() ([]string, bool) { +func (o *TargetConfigProperty) GetOptionsOk() ([]string, bool) { if o == nil || IsNil(o.Options) { return nil, false } @@ -197,7 +197,7 @@ func (o *ProviderProviderTargetProperty) GetOptionsOk() ([]string, bool) { } // HasOptions returns a boolean if a field has been set. -func (o *ProviderProviderTargetProperty) HasOptions() bool { +func (o *TargetConfigProperty) HasOptions() bool { if o != nil && !IsNil(o.Options) { return true } @@ -206,12 +206,12 @@ func (o *ProviderProviderTargetProperty) HasOptions() bool { } // SetOptions gets a reference to the given []string and assigns it to the Options field. -func (o *ProviderProviderTargetProperty) SetOptions(v []string) { +func (o *TargetConfigProperty) SetOptions(v []string) { o.Options = v } // GetSuggestions returns the Suggestions field value if set, zero value otherwise. -func (o *ProviderProviderTargetProperty) GetSuggestions() []string { +func (o *TargetConfigProperty) GetSuggestions() []string { if o == nil || IsNil(o.Suggestions) { var ret []string return ret @@ -221,7 +221,7 @@ func (o *ProviderProviderTargetProperty) GetSuggestions() []string { // GetSuggestionsOk returns a tuple with the Suggestions field value if set, nil otherwise // and a boolean to check if the value has been set. -func (o *ProviderProviderTargetProperty) GetSuggestionsOk() ([]string, bool) { +func (o *TargetConfigProperty) GetSuggestionsOk() ([]string, bool) { if o == nil || IsNil(o.Suggestions) { return nil, false } @@ -229,7 +229,7 @@ func (o *ProviderProviderTargetProperty) GetSuggestionsOk() ([]string, bool) { } // HasSuggestions returns a boolean if a field has been set. -func (o *ProviderProviderTargetProperty) HasSuggestions() bool { +func (o *TargetConfigProperty) HasSuggestions() bool { if o != nil && !IsNil(o.Suggestions) { return true } @@ -238,14 +238,14 @@ func (o *ProviderProviderTargetProperty) HasSuggestions() bool { } // SetSuggestions gets a reference to the given []string and assigns it to the Suggestions field. -func (o *ProviderProviderTargetProperty) SetSuggestions(v []string) { +func (o *TargetConfigProperty) SetSuggestions(v []string) { o.Suggestions = v } // GetType returns the Type field value if set, zero value otherwise. -func (o *ProviderProviderTargetProperty) GetType() ProviderProviderTargetPropertyType { +func (o *TargetConfigProperty) GetType() ModelsTargetConfigPropertyType { if o == nil || IsNil(o.Type) { - var ret ProviderProviderTargetPropertyType + var ret ModelsTargetConfigPropertyType return ret } return *o.Type @@ -253,7 +253,7 @@ func (o *ProviderProviderTargetProperty) GetType() ProviderProviderTargetPropert // GetTypeOk returns a tuple with the Type field value if set, nil otherwise // and a boolean to check if the value has been set. -func (o *ProviderProviderTargetProperty) GetTypeOk() (*ProviderProviderTargetPropertyType, bool) { +func (o *TargetConfigProperty) GetTypeOk() (*ModelsTargetConfigPropertyType, bool) { if o == nil || IsNil(o.Type) { return nil, false } @@ -261,7 +261,7 @@ func (o *ProviderProviderTargetProperty) GetTypeOk() (*ProviderProviderTargetPro } // HasType returns a boolean if a field has been set. -func (o *ProviderProviderTargetProperty) HasType() bool { +func (o *TargetConfigProperty) HasType() bool { if o != nil && !IsNil(o.Type) { return true } @@ -269,12 +269,12 @@ func (o *ProviderProviderTargetProperty) HasType() bool { return false } -// SetType gets a reference to the given ProviderProviderTargetPropertyType and assigns it to the Type field. -func (o *ProviderProviderTargetProperty) SetType(v ProviderProviderTargetPropertyType) { +// SetType gets a reference to the given ModelsTargetConfigPropertyType and assigns it to the Type field. +func (o *TargetConfigProperty) SetType(v ModelsTargetConfigPropertyType) { o.Type = &v } -func (o ProviderProviderTargetProperty) MarshalJSON() ([]byte, error) { +func (o TargetConfigProperty) MarshalJSON() ([]byte, error) { toSerialize, err := o.ToMap() if err != nil { return []byte{}, err @@ -282,7 +282,7 @@ func (o ProviderProviderTargetProperty) MarshalJSON() ([]byte, error) { return json.Marshal(toSerialize) } -func (o ProviderProviderTargetProperty) ToMap() (map[string]interface{}, error) { +func (o TargetConfigProperty) ToMap() (map[string]interface{}, error) { toSerialize := map[string]interface{}{} if !IsNil(o.DefaultValue) { toSerialize["defaultValue"] = o.DefaultValue @@ -308,38 +308,38 @@ func (o ProviderProviderTargetProperty) ToMap() (map[string]interface{}, error) return toSerialize, nil } -type NullableProviderProviderTargetProperty struct { - value *ProviderProviderTargetProperty +type NullableTargetConfigProperty struct { + value *TargetConfigProperty isSet bool } -func (v NullableProviderProviderTargetProperty) Get() *ProviderProviderTargetProperty { +func (v NullableTargetConfigProperty) Get() *TargetConfigProperty { return v.value } -func (v *NullableProviderProviderTargetProperty) Set(val *ProviderProviderTargetProperty) { +func (v *NullableTargetConfigProperty) Set(val *TargetConfigProperty) { v.value = val v.isSet = true } -func (v NullableProviderProviderTargetProperty) IsSet() bool { +func (v NullableTargetConfigProperty) IsSet() bool { return v.isSet } -func (v *NullableProviderProviderTargetProperty) Unset() { +func (v *NullableTargetConfigProperty) Unset() { v.value = nil v.isSet = false } -func NewNullableProviderProviderTargetProperty(val *ProviderProviderTargetProperty) *NullableProviderProviderTargetProperty { - return &NullableProviderProviderTargetProperty{value: val, isSet: true} +func NewNullableTargetConfigProperty(val *TargetConfigProperty) *NullableTargetConfigProperty { + return &NullableTargetConfigProperty{value: val, isSet: true} } -func (v NullableProviderProviderTargetProperty) MarshalJSON() ([]byte, error) { +func (v NullableTargetConfigProperty) MarshalJSON() ([]byte, error) { return json.Marshal(v.value) } -func (v *NullableProviderProviderTargetProperty) UnmarshalJSON(src []byte) error { +func (v *NullableTargetConfigProperty) UnmarshalJSON(src []byte) error { v.isSet = true return json.Unmarshal(src, &v.value) } diff --git a/pkg/apiclient/model_target_dto.go b/pkg/apiclient/model_target_dto.go new file mode 100644 index 0000000000..61830fce30 --- /dev/null +++ b/pkg/apiclient/model_target_dto.go @@ -0,0 +1,496 @@ +/* +Daytona Server API + +Daytona Server API + +API version: v0.0.0-dev +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package apiclient + +import ( + "bytes" + "encoding/json" + "fmt" +) + +// checks if the TargetDTO type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &TargetDTO{} + +// TargetDTO struct for TargetDTO +type TargetDTO struct { + Default bool `json:"default"` + EnvVars map[string]string `json:"envVars"` + Id string `json:"id"` + LastJob *Job `json:"lastJob,omitempty"` + LastJobId *string `json:"lastJobId,omitempty"` + Metadata *TargetMetadata `json:"metadata,omitempty"` + Name string `json:"name"` + ProviderMetadata *string `json:"providerMetadata,omitempty"` + State ResourceState `json:"state"` + TargetConfig TargetConfig `json:"targetConfig"` + TargetConfigId string `json:"targetConfigId"` + Workspaces []Workspace `json:"workspaces"` +} + +type _TargetDTO TargetDTO + +// NewTargetDTO instantiates a new TargetDTO object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewTargetDTO(default_ bool, envVars map[string]string, id string, name string, state ResourceState, targetConfig TargetConfig, targetConfigId string, workspaces []Workspace) *TargetDTO { + this := TargetDTO{} + this.Default = default_ + this.EnvVars = envVars + this.Id = id + this.Name = name + this.State = state + this.TargetConfig = targetConfig + this.TargetConfigId = targetConfigId + this.Workspaces = workspaces + return &this +} + +// NewTargetDTOWithDefaults instantiates a new TargetDTO object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewTargetDTOWithDefaults() *TargetDTO { + this := TargetDTO{} + return &this +} + +// GetDefault returns the Default field value +func (o *TargetDTO) GetDefault() bool { + if o == nil { + var ret bool + return ret + } + + return o.Default +} + +// GetDefaultOk returns a tuple with the Default field value +// and a boolean to check if the value has been set. +func (o *TargetDTO) GetDefaultOk() (*bool, bool) { + if o == nil { + return nil, false + } + return &o.Default, true +} + +// SetDefault sets field value +func (o *TargetDTO) SetDefault(v bool) { + o.Default = v +} + +// GetEnvVars returns the EnvVars field value +func (o *TargetDTO) GetEnvVars() map[string]string { + if o == nil { + var ret map[string]string + return ret + } + + return o.EnvVars +} + +// GetEnvVarsOk returns a tuple with the EnvVars field value +// and a boolean to check if the value has been set. +func (o *TargetDTO) GetEnvVarsOk() (*map[string]string, bool) { + if o == nil { + return nil, false + } + return &o.EnvVars, true +} + +// SetEnvVars sets field value +func (o *TargetDTO) SetEnvVars(v map[string]string) { + o.EnvVars = v +} + +// GetId returns the Id field value +func (o *TargetDTO) GetId() string { + if o == nil { + var ret string + return ret + } + + return o.Id +} + +// GetIdOk returns a tuple with the Id field value +// and a boolean to check if the value has been set. +func (o *TargetDTO) GetIdOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Id, true +} + +// SetId sets field value +func (o *TargetDTO) SetId(v string) { + o.Id = v +} + +// GetLastJob returns the LastJob field value if set, zero value otherwise. +func (o *TargetDTO) GetLastJob() Job { + if o == nil || IsNil(o.LastJob) { + var ret Job + return ret + } + return *o.LastJob +} + +// GetLastJobOk returns a tuple with the LastJob field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *TargetDTO) GetLastJobOk() (*Job, bool) { + if o == nil || IsNil(o.LastJob) { + return nil, false + } + return o.LastJob, true +} + +// HasLastJob returns a boolean if a field has been set. +func (o *TargetDTO) HasLastJob() bool { + if o != nil && !IsNil(o.LastJob) { + return true + } + + return false +} + +// SetLastJob gets a reference to the given Job and assigns it to the LastJob field. +func (o *TargetDTO) SetLastJob(v Job) { + o.LastJob = &v +} + +// GetLastJobId returns the LastJobId field value if set, zero value otherwise. +func (o *TargetDTO) GetLastJobId() string { + if o == nil || IsNil(o.LastJobId) { + var ret string + return ret + } + return *o.LastJobId +} + +// GetLastJobIdOk returns a tuple with the LastJobId field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *TargetDTO) GetLastJobIdOk() (*string, bool) { + if o == nil || IsNil(o.LastJobId) { + return nil, false + } + return o.LastJobId, true +} + +// HasLastJobId returns a boolean if a field has been set. +func (o *TargetDTO) HasLastJobId() bool { + if o != nil && !IsNil(o.LastJobId) { + return true + } + + return false +} + +// SetLastJobId gets a reference to the given string and assigns it to the LastJobId field. +func (o *TargetDTO) SetLastJobId(v string) { + o.LastJobId = &v +} + +// GetMetadata returns the Metadata field value if set, zero value otherwise. +func (o *TargetDTO) GetMetadata() TargetMetadata { + if o == nil || IsNil(o.Metadata) { + var ret TargetMetadata + return ret + } + return *o.Metadata +} + +// GetMetadataOk returns a tuple with the Metadata field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *TargetDTO) GetMetadataOk() (*TargetMetadata, bool) { + if o == nil || IsNil(o.Metadata) { + return nil, false + } + return o.Metadata, true +} + +// HasMetadata returns a boolean if a field has been set. +func (o *TargetDTO) HasMetadata() bool { + if o != nil && !IsNil(o.Metadata) { + return true + } + + return false +} + +// SetMetadata gets a reference to the given TargetMetadata and assigns it to the Metadata field. +func (o *TargetDTO) SetMetadata(v TargetMetadata) { + o.Metadata = &v +} + +// GetName returns the Name field value +func (o *TargetDTO) GetName() string { + if o == nil { + var ret string + return ret + } + + return o.Name +} + +// GetNameOk returns a tuple with the Name field value +// and a boolean to check if the value has been set. +func (o *TargetDTO) GetNameOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Name, true +} + +// SetName sets field value +func (o *TargetDTO) SetName(v string) { + o.Name = v +} + +// GetProviderMetadata returns the ProviderMetadata field value if set, zero value otherwise. +func (o *TargetDTO) GetProviderMetadata() string { + if o == nil || IsNil(o.ProviderMetadata) { + var ret string + return ret + } + return *o.ProviderMetadata +} + +// GetProviderMetadataOk returns a tuple with the ProviderMetadata field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *TargetDTO) GetProviderMetadataOk() (*string, bool) { + if o == nil || IsNil(o.ProviderMetadata) { + return nil, false + } + return o.ProviderMetadata, true +} + +// HasProviderMetadata returns a boolean if a field has been set. +func (o *TargetDTO) HasProviderMetadata() bool { + if o != nil && !IsNil(o.ProviderMetadata) { + return true + } + + return false +} + +// SetProviderMetadata gets a reference to the given string and assigns it to the ProviderMetadata field. +func (o *TargetDTO) SetProviderMetadata(v string) { + o.ProviderMetadata = &v +} + +// GetState returns the State field value +func (o *TargetDTO) GetState() ResourceState { + if o == nil { + var ret ResourceState + return ret + } + + return o.State +} + +// GetStateOk returns a tuple with the State field value +// and a boolean to check if the value has been set. +func (o *TargetDTO) GetStateOk() (*ResourceState, bool) { + if o == nil { + return nil, false + } + return &o.State, true +} + +// SetState sets field value +func (o *TargetDTO) SetState(v ResourceState) { + o.State = v +} + +// GetTargetConfig returns the TargetConfig field value +func (o *TargetDTO) GetTargetConfig() TargetConfig { + if o == nil { + var ret TargetConfig + return ret + } + + return o.TargetConfig +} + +// GetTargetConfigOk returns a tuple with the TargetConfig field value +// and a boolean to check if the value has been set. +func (o *TargetDTO) GetTargetConfigOk() (*TargetConfig, bool) { + if o == nil { + return nil, false + } + return &o.TargetConfig, true +} + +// SetTargetConfig sets field value +func (o *TargetDTO) SetTargetConfig(v TargetConfig) { + o.TargetConfig = v +} + +// GetTargetConfigId returns the TargetConfigId field value +func (o *TargetDTO) GetTargetConfigId() string { + if o == nil { + var ret string + return ret + } + + return o.TargetConfigId +} + +// GetTargetConfigIdOk returns a tuple with the TargetConfigId field value +// and a boolean to check if the value has been set. +func (o *TargetDTO) GetTargetConfigIdOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.TargetConfigId, true +} + +// SetTargetConfigId sets field value +func (o *TargetDTO) SetTargetConfigId(v string) { + o.TargetConfigId = v +} + +// GetWorkspaces returns the Workspaces field value +func (o *TargetDTO) GetWorkspaces() []Workspace { + if o == nil { + var ret []Workspace + return ret + } + + return o.Workspaces +} + +// GetWorkspacesOk returns a tuple with the Workspaces field value +// and a boolean to check if the value has been set. +func (o *TargetDTO) GetWorkspacesOk() ([]Workspace, bool) { + if o == nil { + return nil, false + } + return o.Workspaces, true +} + +// SetWorkspaces sets field value +func (o *TargetDTO) SetWorkspaces(v []Workspace) { + o.Workspaces = v +} + +func (o TargetDTO) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o TargetDTO) ToMap() (map[string]interface{}, error) { + toSerialize := map[string]interface{}{} + toSerialize["default"] = o.Default + toSerialize["envVars"] = o.EnvVars + toSerialize["id"] = o.Id + if !IsNil(o.LastJob) { + toSerialize["lastJob"] = o.LastJob + } + if !IsNil(o.LastJobId) { + toSerialize["lastJobId"] = o.LastJobId + } + if !IsNil(o.Metadata) { + toSerialize["metadata"] = o.Metadata + } + toSerialize["name"] = o.Name + if !IsNil(o.ProviderMetadata) { + toSerialize["providerMetadata"] = o.ProviderMetadata + } + toSerialize["state"] = o.State + toSerialize["targetConfig"] = o.TargetConfig + toSerialize["targetConfigId"] = o.TargetConfigId + toSerialize["workspaces"] = o.Workspaces + return toSerialize, nil +} + +func (o *TargetDTO) UnmarshalJSON(data []byte) (err error) { + // This validates that all required properties are included in the JSON object + // by unmarshalling the object into a generic map with string keys and checking + // that every required field exists as a key in the generic map. + requiredProperties := []string{ + "default", + "envVars", + "id", + "name", + "state", + "targetConfig", + "targetConfigId", + "workspaces", + } + + allProperties := make(map[string]interface{}) + + err = json.Unmarshal(data, &allProperties) + + if err != nil { + return err + } + + for _, requiredProperty := range requiredProperties { + if _, exists := allProperties[requiredProperty]; !exists { + return fmt.Errorf("no value given for required property %v", requiredProperty) + } + } + + varTargetDTO := _TargetDTO{} + + decoder := json.NewDecoder(bytes.NewReader(data)) + decoder.DisallowUnknownFields() + err = decoder.Decode(&varTargetDTO) + + if err != nil { + return err + } + + *o = TargetDTO(varTargetDTO) + + return err +} + +type NullableTargetDTO struct { + value *TargetDTO + isSet bool +} + +func (v NullableTargetDTO) Get() *TargetDTO { + return v.value +} + +func (v *NullableTargetDTO) Set(val *TargetDTO) { + v.value = val + v.isSet = true +} + +func (v NullableTargetDTO) IsSet() bool { + return v.isSet +} + +func (v *NullableTargetDTO) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableTargetDTO(val *TargetDTO) *NullableTargetDTO { + return &NullableTargetDTO{value: val, isSet: true} +} + +func (v NullableTargetDTO) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableTargetDTO) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/pkg/apiclient/model_target_metadata.go b/pkg/apiclient/model_target_metadata.go new file mode 100644 index 0000000000..446293be45 --- /dev/null +++ b/pkg/apiclient/model_target_metadata.go @@ -0,0 +1,212 @@ +/* +Daytona Server API + +Daytona Server API + +API version: v0.0.0-dev +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package apiclient + +import ( + "bytes" + "encoding/json" + "fmt" +) + +// checks if the TargetMetadata type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &TargetMetadata{} + +// TargetMetadata struct for TargetMetadata +type TargetMetadata struct { + TargetId string `json:"targetId"` + UpdatedAt string `json:"updatedAt"` + Uptime int32 `json:"uptime"` +} + +type _TargetMetadata TargetMetadata + +// NewTargetMetadata instantiates a new TargetMetadata object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewTargetMetadata(targetId string, updatedAt string, uptime int32) *TargetMetadata { + this := TargetMetadata{} + this.TargetId = targetId + this.UpdatedAt = updatedAt + this.Uptime = uptime + return &this +} + +// NewTargetMetadataWithDefaults instantiates a new TargetMetadata object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewTargetMetadataWithDefaults() *TargetMetadata { + this := TargetMetadata{} + return &this +} + +// GetTargetId returns the TargetId field value +func (o *TargetMetadata) GetTargetId() string { + if o == nil { + var ret string + return ret + } + + return o.TargetId +} + +// GetTargetIdOk returns a tuple with the TargetId field value +// and a boolean to check if the value has been set. +func (o *TargetMetadata) GetTargetIdOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.TargetId, true +} + +// SetTargetId sets field value +func (o *TargetMetadata) SetTargetId(v string) { + o.TargetId = v +} + +// GetUpdatedAt returns the UpdatedAt field value +func (o *TargetMetadata) GetUpdatedAt() string { + if o == nil { + var ret string + return ret + } + + return o.UpdatedAt +} + +// GetUpdatedAtOk returns a tuple with the UpdatedAt field value +// and a boolean to check if the value has been set. +func (o *TargetMetadata) GetUpdatedAtOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.UpdatedAt, true +} + +// SetUpdatedAt sets field value +func (o *TargetMetadata) SetUpdatedAt(v string) { + o.UpdatedAt = v +} + +// GetUptime returns the Uptime field value +func (o *TargetMetadata) GetUptime() int32 { + if o == nil { + var ret int32 + return ret + } + + return o.Uptime +} + +// GetUptimeOk returns a tuple with the Uptime field value +// and a boolean to check if the value has been set. +func (o *TargetMetadata) GetUptimeOk() (*int32, bool) { + if o == nil { + return nil, false + } + return &o.Uptime, true +} + +// SetUptime sets field value +func (o *TargetMetadata) SetUptime(v int32) { + o.Uptime = v +} + +func (o TargetMetadata) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o TargetMetadata) ToMap() (map[string]interface{}, error) { + toSerialize := map[string]interface{}{} + toSerialize["targetId"] = o.TargetId + toSerialize["updatedAt"] = o.UpdatedAt + toSerialize["uptime"] = o.Uptime + return toSerialize, nil +} + +func (o *TargetMetadata) UnmarshalJSON(data []byte) (err error) { + // This validates that all required properties are included in the JSON object + // by unmarshalling the object into a generic map with string keys and checking + // that every required field exists as a key in the generic map. + requiredProperties := []string{ + "targetId", + "updatedAt", + "uptime", + } + + allProperties := make(map[string]interface{}) + + err = json.Unmarshal(data, &allProperties) + + if err != nil { + return err + } + + for _, requiredProperty := range requiredProperties { + if _, exists := allProperties[requiredProperty]; !exists { + return fmt.Errorf("no value given for required property %v", requiredProperty) + } + } + + varTargetMetadata := _TargetMetadata{} + + decoder := json.NewDecoder(bytes.NewReader(data)) + decoder.DisallowUnknownFields() + err = decoder.Decode(&varTargetMetadata) + + if err != nil { + return err + } + + *o = TargetMetadata(varTargetMetadata) + + return err +} + +type NullableTargetMetadata struct { + value *TargetMetadata + isSet bool +} + +func (v NullableTargetMetadata) Get() *TargetMetadata { + return v.value +} + +func (v *NullableTargetMetadata) Set(val *TargetMetadata) { + v.value = val + v.isSet = true +} + +func (v NullableTargetMetadata) IsSet() bool { + return v.isSet +} + +func (v *NullableTargetMetadata) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableTargetMetadata(val *TargetMetadata) *NullableTargetMetadata { + return &NullableTargetMetadata{value: val, isSet: true} +} + +func (v NullableTargetMetadata) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableTargetMetadata) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/pkg/apiclient/model_update_job_state.go b/pkg/apiclient/model_update_job_state.go new file mode 100644 index 0000000000..87d667a09f --- /dev/null +++ b/pkg/apiclient/model_update_job_state.go @@ -0,0 +1,192 @@ +/* +Daytona Server API + +Daytona Server API + +API version: v0.0.0-dev +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package apiclient + +import ( + "bytes" + "encoding/json" + "fmt" +) + +// checks if the UpdateJobState type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &UpdateJobState{} + +// UpdateJobState struct for UpdateJobState +type UpdateJobState struct { + ErrorMessage *string `json:"errorMessage,omitempty"` + State JobState `json:"state"` +} + +type _UpdateJobState UpdateJobState + +// NewUpdateJobState instantiates a new UpdateJobState object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewUpdateJobState(state JobState) *UpdateJobState { + this := UpdateJobState{} + this.State = state + return &this +} + +// NewUpdateJobStateWithDefaults instantiates a new UpdateJobState object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewUpdateJobStateWithDefaults() *UpdateJobState { + this := UpdateJobState{} + return &this +} + +// GetErrorMessage returns the ErrorMessage field value if set, zero value otherwise. +func (o *UpdateJobState) GetErrorMessage() string { + if o == nil || IsNil(o.ErrorMessage) { + var ret string + return ret + } + return *o.ErrorMessage +} + +// GetErrorMessageOk returns a tuple with the ErrorMessage field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *UpdateJobState) GetErrorMessageOk() (*string, bool) { + if o == nil || IsNil(o.ErrorMessage) { + return nil, false + } + return o.ErrorMessage, true +} + +// HasErrorMessage returns a boolean if a field has been set. +func (o *UpdateJobState) HasErrorMessage() bool { + if o != nil && !IsNil(o.ErrorMessage) { + return true + } + + return false +} + +// SetErrorMessage gets a reference to the given string and assigns it to the ErrorMessage field. +func (o *UpdateJobState) SetErrorMessage(v string) { + o.ErrorMessage = &v +} + +// GetState returns the State field value +func (o *UpdateJobState) GetState() JobState { + if o == nil { + var ret JobState + return ret + } + + return o.State +} + +// GetStateOk returns a tuple with the State field value +// and a boolean to check if the value has been set. +func (o *UpdateJobState) GetStateOk() (*JobState, bool) { + if o == nil { + return nil, false + } + return &o.State, true +} + +// SetState sets field value +func (o *UpdateJobState) SetState(v JobState) { + o.State = v +} + +func (o UpdateJobState) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o UpdateJobState) ToMap() (map[string]interface{}, error) { + toSerialize := map[string]interface{}{} + if !IsNil(o.ErrorMessage) { + toSerialize["errorMessage"] = o.ErrorMessage + } + toSerialize["state"] = o.State + return toSerialize, nil +} + +func (o *UpdateJobState) UnmarshalJSON(data []byte) (err error) { + // This validates that all required properties are included in the JSON object + // by unmarshalling the object into a generic map with string keys and checking + // that every required field exists as a key in the generic map. + requiredProperties := []string{ + "state", + } + + allProperties := make(map[string]interface{}) + + err = json.Unmarshal(data, &allProperties) + + if err != nil { + return err + } + + for _, requiredProperty := range requiredProperties { + if _, exists := allProperties[requiredProperty]; !exists { + return fmt.Errorf("no value given for required property %v", requiredProperty) + } + } + + varUpdateJobState := _UpdateJobState{} + + decoder := json.NewDecoder(bytes.NewReader(data)) + decoder.DisallowUnknownFields() + err = decoder.Decode(&varUpdateJobState) + + if err != nil { + return err + } + + *o = UpdateJobState(varUpdateJobState) + + return err +} + +type NullableUpdateJobState struct { + value *UpdateJobState + isSet bool +} + +func (v NullableUpdateJobState) Get() *UpdateJobState { + return v.value +} + +func (v *NullableUpdateJobState) Set(val *UpdateJobState) { + v.value = val + v.isSet = true +} + +func (v NullableUpdateJobState) IsSet() bool { + return v.isSet +} + +func (v *NullableUpdateJobState) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableUpdateJobState(val *UpdateJobState) *NullableUpdateJobState { + return &NullableUpdateJobState{value: val, isSet: true} +} + +func (v NullableUpdateJobState) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableUpdateJobState) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/pkg/apiclient/model_update_runner_metadata_dto.go b/pkg/apiclient/model_update_runner_metadata_dto.go new file mode 100644 index 0000000000..0e3446e401 --- /dev/null +++ b/pkg/apiclient/model_update_runner_metadata_dto.go @@ -0,0 +1,220 @@ +/* +Daytona Server API + +Daytona Server API + +API version: v0.0.0-dev +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package apiclient + +import ( + "bytes" + "encoding/json" + "fmt" +) + +// checks if the UpdateRunnerMetadataDTO type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &UpdateRunnerMetadataDTO{} + +// UpdateRunnerMetadataDTO struct for UpdateRunnerMetadataDTO +type UpdateRunnerMetadataDTO struct { + Providers []ProviderInfo `json:"providers"` + RunningJobs *int32 `json:"runningJobs,omitempty"` + Uptime int32 `json:"uptime"` +} + +type _UpdateRunnerMetadataDTO UpdateRunnerMetadataDTO + +// NewUpdateRunnerMetadataDTO instantiates a new UpdateRunnerMetadataDTO object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewUpdateRunnerMetadataDTO(providers []ProviderInfo, uptime int32) *UpdateRunnerMetadataDTO { + this := UpdateRunnerMetadataDTO{} + this.Providers = providers + this.Uptime = uptime + return &this +} + +// NewUpdateRunnerMetadataDTOWithDefaults instantiates a new UpdateRunnerMetadataDTO object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewUpdateRunnerMetadataDTOWithDefaults() *UpdateRunnerMetadataDTO { + this := UpdateRunnerMetadataDTO{} + return &this +} + +// GetProviders returns the Providers field value +func (o *UpdateRunnerMetadataDTO) GetProviders() []ProviderInfo { + if o == nil { + var ret []ProviderInfo + return ret + } + + return o.Providers +} + +// GetProvidersOk returns a tuple with the Providers field value +// and a boolean to check if the value has been set. +func (o *UpdateRunnerMetadataDTO) GetProvidersOk() ([]ProviderInfo, bool) { + if o == nil { + return nil, false + } + return o.Providers, true +} + +// SetProviders sets field value +func (o *UpdateRunnerMetadataDTO) SetProviders(v []ProviderInfo) { + o.Providers = v +} + +// GetRunningJobs returns the RunningJobs field value if set, zero value otherwise. +func (o *UpdateRunnerMetadataDTO) GetRunningJobs() int32 { + if o == nil || IsNil(o.RunningJobs) { + var ret int32 + return ret + } + return *o.RunningJobs +} + +// GetRunningJobsOk returns a tuple with the RunningJobs field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *UpdateRunnerMetadataDTO) GetRunningJobsOk() (*int32, bool) { + if o == nil || IsNil(o.RunningJobs) { + return nil, false + } + return o.RunningJobs, true +} + +// HasRunningJobs returns a boolean if a field has been set. +func (o *UpdateRunnerMetadataDTO) HasRunningJobs() bool { + if o != nil && !IsNil(o.RunningJobs) { + return true + } + + return false +} + +// SetRunningJobs gets a reference to the given int32 and assigns it to the RunningJobs field. +func (o *UpdateRunnerMetadataDTO) SetRunningJobs(v int32) { + o.RunningJobs = &v +} + +// GetUptime returns the Uptime field value +func (o *UpdateRunnerMetadataDTO) GetUptime() int32 { + if o == nil { + var ret int32 + return ret + } + + return o.Uptime +} + +// GetUptimeOk returns a tuple with the Uptime field value +// and a boolean to check if the value has been set. +func (o *UpdateRunnerMetadataDTO) GetUptimeOk() (*int32, bool) { + if o == nil { + return nil, false + } + return &o.Uptime, true +} + +// SetUptime sets field value +func (o *UpdateRunnerMetadataDTO) SetUptime(v int32) { + o.Uptime = v +} + +func (o UpdateRunnerMetadataDTO) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o UpdateRunnerMetadataDTO) ToMap() (map[string]interface{}, error) { + toSerialize := map[string]interface{}{} + toSerialize["providers"] = o.Providers + if !IsNil(o.RunningJobs) { + toSerialize["runningJobs"] = o.RunningJobs + } + toSerialize["uptime"] = o.Uptime + return toSerialize, nil +} + +func (o *UpdateRunnerMetadataDTO) UnmarshalJSON(data []byte) (err error) { + // This validates that all required properties are included in the JSON object + // by unmarshalling the object into a generic map with string keys and checking + // that every required field exists as a key in the generic map. + requiredProperties := []string{ + "providers", + "uptime", + } + + allProperties := make(map[string]interface{}) + + err = json.Unmarshal(data, &allProperties) + + if err != nil { + return err + } + + for _, requiredProperty := range requiredProperties { + if _, exists := allProperties[requiredProperty]; !exists { + return fmt.Errorf("no value given for required property %v", requiredProperty) + } + } + + varUpdateRunnerMetadataDTO := _UpdateRunnerMetadataDTO{} + + decoder := json.NewDecoder(bytes.NewReader(data)) + decoder.DisallowUnknownFields() + err = decoder.Decode(&varUpdateRunnerMetadataDTO) + + if err != nil { + return err + } + + *o = UpdateRunnerMetadataDTO(varUpdateRunnerMetadataDTO) + + return err +} + +type NullableUpdateRunnerMetadataDTO struct { + value *UpdateRunnerMetadataDTO + isSet bool +} + +func (v NullableUpdateRunnerMetadataDTO) Get() *UpdateRunnerMetadataDTO { + return v.value +} + +func (v *NullableUpdateRunnerMetadataDTO) Set(val *UpdateRunnerMetadataDTO) { + v.value = val + v.isSet = true +} + +func (v NullableUpdateRunnerMetadataDTO) IsSet() bool { + return v.isSet +} + +func (v *NullableUpdateRunnerMetadataDTO) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableUpdateRunnerMetadataDTO(val *UpdateRunnerMetadataDTO) *NullableUpdateRunnerMetadataDTO { + return &NullableUpdateRunnerMetadataDTO{value: val, isSet: true} +} + +func (v NullableUpdateRunnerMetadataDTO) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableUpdateRunnerMetadataDTO) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/pkg/apiclient/model_update_target_metadata_dto.go b/pkg/apiclient/model_update_target_metadata_dto.go new file mode 100644 index 0000000000..da46e7e7c3 --- /dev/null +++ b/pkg/apiclient/model_update_target_metadata_dto.go @@ -0,0 +1,156 @@ +/* +Daytona Server API + +Daytona Server API + +API version: v0.0.0-dev +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package apiclient + +import ( + "bytes" + "encoding/json" + "fmt" +) + +// checks if the UpdateTargetMetadataDTO type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &UpdateTargetMetadataDTO{} + +// UpdateTargetMetadataDTO struct for UpdateTargetMetadataDTO +type UpdateTargetMetadataDTO struct { + Uptime int32 `json:"uptime"` +} + +type _UpdateTargetMetadataDTO UpdateTargetMetadataDTO + +// NewUpdateTargetMetadataDTO instantiates a new UpdateTargetMetadataDTO object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewUpdateTargetMetadataDTO(uptime int32) *UpdateTargetMetadataDTO { + this := UpdateTargetMetadataDTO{} + this.Uptime = uptime + return &this +} + +// NewUpdateTargetMetadataDTOWithDefaults instantiates a new UpdateTargetMetadataDTO object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewUpdateTargetMetadataDTOWithDefaults() *UpdateTargetMetadataDTO { + this := UpdateTargetMetadataDTO{} + return &this +} + +// GetUptime returns the Uptime field value +func (o *UpdateTargetMetadataDTO) GetUptime() int32 { + if o == nil { + var ret int32 + return ret + } + + return o.Uptime +} + +// GetUptimeOk returns a tuple with the Uptime field value +// and a boolean to check if the value has been set. +func (o *UpdateTargetMetadataDTO) GetUptimeOk() (*int32, bool) { + if o == nil { + return nil, false + } + return &o.Uptime, true +} + +// SetUptime sets field value +func (o *UpdateTargetMetadataDTO) SetUptime(v int32) { + o.Uptime = v +} + +func (o UpdateTargetMetadataDTO) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o UpdateTargetMetadataDTO) ToMap() (map[string]interface{}, error) { + toSerialize := map[string]interface{}{} + toSerialize["uptime"] = o.Uptime + return toSerialize, nil +} + +func (o *UpdateTargetMetadataDTO) UnmarshalJSON(data []byte) (err error) { + // This validates that all required properties are included in the JSON object + // by unmarshalling the object into a generic map with string keys and checking + // that every required field exists as a key in the generic map. + requiredProperties := []string{ + "uptime", + } + + allProperties := make(map[string]interface{}) + + err = json.Unmarshal(data, &allProperties) + + if err != nil { + return err + } + + for _, requiredProperty := range requiredProperties { + if _, exists := allProperties[requiredProperty]; !exists { + return fmt.Errorf("no value given for required property %v", requiredProperty) + } + } + + varUpdateTargetMetadataDTO := _UpdateTargetMetadataDTO{} + + decoder := json.NewDecoder(bytes.NewReader(data)) + decoder.DisallowUnknownFields() + err = decoder.Decode(&varUpdateTargetMetadataDTO) + + if err != nil { + return err + } + + *o = UpdateTargetMetadataDTO(varUpdateTargetMetadataDTO) + + return err +} + +type NullableUpdateTargetMetadataDTO struct { + value *UpdateTargetMetadataDTO + isSet bool +} + +func (v NullableUpdateTargetMetadataDTO) Get() *UpdateTargetMetadataDTO { + return v.value +} + +func (v *NullableUpdateTargetMetadataDTO) Set(val *UpdateTargetMetadataDTO) { + v.value = val + v.isSet = true +} + +func (v NullableUpdateTargetMetadataDTO) IsSet() bool { + return v.isSet +} + +func (v *NullableUpdateTargetMetadataDTO) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableUpdateTargetMetadataDTO(val *UpdateTargetMetadataDTO) *NullableUpdateTargetMetadataDTO { + return &NullableUpdateTargetMetadataDTO{value: val, isSet: true} +} + +func (v NullableUpdateTargetMetadataDTO) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableUpdateTargetMetadataDTO) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/pkg/apiclient/model_update_target_provider_metadata_dto.go b/pkg/apiclient/model_update_target_provider_metadata_dto.go new file mode 100644 index 0000000000..280accbccf --- /dev/null +++ b/pkg/apiclient/model_update_target_provider_metadata_dto.go @@ -0,0 +1,156 @@ +/* +Daytona Server API + +Daytona Server API + +API version: v0.0.0-dev +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package apiclient + +import ( + "bytes" + "encoding/json" + "fmt" +) + +// checks if the UpdateTargetProviderMetadataDTO type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &UpdateTargetProviderMetadataDTO{} + +// UpdateTargetProviderMetadataDTO struct for UpdateTargetProviderMetadataDTO +type UpdateTargetProviderMetadataDTO struct { + Metadata string `json:"metadata"` +} + +type _UpdateTargetProviderMetadataDTO UpdateTargetProviderMetadataDTO + +// NewUpdateTargetProviderMetadataDTO instantiates a new UpdateTargetProviderMetadataDTO object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewUpdateTargetProviderMetadataDTO(metadata string) *UpdateTargetProviderMetadataDTO { + this := UpdateTargetProviderMetadataDTO{} + this.Metadata = metadata + return &this +} + +// NewUpdateTargetProviderMetadataDTOWithDefaults instantiates a new UpdateTargetProviderMetadataDTO object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewUpdateTargetProviderMetadataDTOWithDefaults() *UpdateTargetProviderMetadataDTO { + this := UpdateTargetProviderMetadataDTO{} + return &this +} + +// GetMetadata returns the Metadata field value +func (o *UpdateTargetProviderMetadataDTO) GetMetadata() string { + if o == nil { + var ret string + return ret + } + + return o.Metadata +} + +// GetMetadataOk returns a tuple with the Metadata field value +// and a boolean to check if the value has been set. +func (o *UpdateTargetProviderMetadataDTO) GetMetadataOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Metadata, true +} + +// SetMetadata sets field value +func (o *UpdateTargetProviderMetadataDTO) SetMetadata(v string) { + o.Metadata = v +} + +func (o UpdateTargetProviderMetadataDTO) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o UpdateTargetProviderMetadataDTO) ToMap() (map[string]interface{}, error) { + toSerialize := map[string]interface{}{} + toSerialize["metadata"] = o.Metadata + return toSerialize, nil +} + +func (o *UpdateTargetProviderMetadataDTO) UnmarshalJSON(data []byte) (err error) { + // This validates that all required properties are included in the JSON object + // by unmarshalling the object into a generic map with string keys and checking + // that every required field exists as a key in the generic map. + requiredProperties := []string{ + "metadata", + } + + allProperties := make(map[string]interface{}) + + err = json.Unmarshal(data, &allProperties) + + if err != nil { + return err + } + + for _, requiredProperty := range requiredProperties { + if _, exists := allProperties[requiredProperty]; !exists { + return fmt.Errorf("no value given for required property %v", requiredProperty) + } + } + + varUpdateTargetProviderMetadataDTO := _UpdateTargetProviderMetadataDTO{} + + decoder := json.NewDecoder(bytes.NewReader(data)) + decoder.DisallowUnknownFields() + err = decoder.Decode(&varUpdateTargetProviderMetadataDTO) + + if err != nil { + return err + } + + *o = UpdateTargetProviderMetadataDTO(varUpdateTargetProviderMetadataDTO) + + return err +} + +type NullableUpdateTargetProviderMetadataDTO struct { + value *UpdateTargetProviderMetadataDTO + isSet bool +} + +func (v NullableUpdateTargetProviderMetadataDTO) Get() *UpdateTargetProviderMetadataDTO { + return v.value +} + +func (v *NullableUpdateTargetProviderMetadataDTO) Set(val *UpdateTargetProviderMetadataDTO) { + v.value = val + v.isSet = true +} + +func (v NullableUpdateTargetProviderMetadataDTO) IsSet() bool { + return v.isSet +} + +func (v *NullableUpdateTargetProviderMetadataDTO) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableUpdateTargetProviderMetadataDTO(val *UpdateTargetProviderMetadataDTO) *NullableUpdateTargetProviderMetadataDTO { + return &NullableUpdateTargetProviderMetadataDTO{value: val, isSet: true} +} + +func (v NullableUpdateTargetProviderMetadataDTO) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableUpdateTargetProviderMetadataDTO) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/pkg/apiclient/model_set_project_state.go b/pkg/apiclient/model_update_workspace_metadata_dto.go similarity index 56% rename from pkg/apiclient/model_set_project_state.go rename to pkg/apiclient/model_update_workspace_metadata_dto.go index eebfd1d605..55d663cdb3 100644 --- a/pkg/apiclient/model_set_project_state.go +++ b/pkg/apiclient/model_update_workspace_metadata_dto.go @@ -16,37 +16,37 @@ import ( "fmt" ) -// checks if the SetProjectState type satisfies the MappedNullable interface at compile time -var _ MappedNullable = &SetProjectState{} +// checks if the UpdateWorkspaceMetadataDTO type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &UpdateWorkspaceMetadataDTO{} -// SetProjectState struct for SetProjectState -type SetProjectState struct { +// UpdateWorkspaceMetadataDTO struct for UpdateWorkspaceMetadataDTO +type UpdateWorkspaceMetadataDTO struct { GitStatus *GitStatus `json:"gitStatus,omitempty"` Uptime int32 `json:"uptime"` } -type _SetProjectState SetProjectState +type _UpdateWorkspaceMetadataDTO UpdateWorkspaceMetadataDTO -// NewSetProjectState instantiates a new SetProjectState object +// NewUpdateWorkspaceMetadataDTO instantiates a new UpdateWorkspaceMetadataDTO object // This constructor will assign default values to properties that have it defined, // and makes sure properties required by API are set, but the set of arguments // will change when the set of required properties is changed -func NewSetProjectState(uptime int32) *SetProjectState { - this := SetProjectState{} +func NewUpdateWorkspaceMetadataDTO(uptime int32) *UpdateWorkspaceMetadataDTO { + this := UpdateWorkspaceMetadataDTO{} this.Uptime = uptime return &this } -// NewSetProjectStateWithDefaults instantiates a new SetProjectState object +// NewUpdateWorkspaceMetadataDTOWithDefaults instantiates a new UpdateWorkspaceMetadataDTO object // This constructor will only assign default values to properties that have it defined, // but it doesn't guarantee that properties required by API are set -func NewSetProjectStateWithDefaults() *SetProjectState { - this := SetProjectState{} +func NewUpdateWorkspaceMetadataDTOWithDefaults() *UpdateWorkspaceMetadataDTO { + this := UpdateWorkspaceMetadataDTO{} return &this } // GetGitStatus returns the GitStatus field value if set, zero value otherwise. -func (o *SetProjectState) GetGitStatus() GitStatus { +func (o *UpdateWorkspaceMetadataDTO) GetGitStatus() GitStatus { if o == nil || IsNil(o.GitStatus) { var ret GitStatus return ret @@ -56,7 +56,7 @@ func (o *SetProjectState) GetGitStatus() GitStatus { // GetGitStatusOk returns a tuple with the GitStatus field value if set, nil otherwise // and a boolean to check if the value has been set. -func (o *SetProjectState) GetGitStatusOk() (*GitStatus, bool) { +func (o *UpdateWorkspaceMetadataDTO) GetGitStatusOk() (*GitStatus, bool) { if o == nil || IsNil(o.GitStatus) { return nil, false } @@ -64,7 +64,7 @@ func (o *SetProjectState) GetGitStatusOk() (*GitStatus, bool) { } // HasGitStatus returns a boolean if a field has been set. -func (o *SetProjectState) HasGitStatus() bool { +func (o *UpdateWorkspaceMetadataDTO) HasGitStatus() bool { if o != nil && !IsNil(o.GitStatus) { return true } @@ -73,12 +73,12 @@ func (o *SetProjectState) HasGitStatus() bool { } // SetGitStatus gets a reference to the given GitStatus and assigns it to the GitStatus field. -func (o *SetProjectState) SetGitStatus(v GitStatus) { +func (o *UpdateWorkspaceMetadataDTO) SetGitStatus(v GitStatus) { o.GitStatus = &v } // GetUptime returns the Uptime field value -func (o *SetProjectState) GetUptime() int32 { +func (o *UpdateWorkspaceMetadataDTO) GetUptime() int32 { if o == nil { var ret int32 return ret @@ -89,7 +89,7 @@ func (o *SetProjectState) GetUptime() int32 { // GetUptimeOk returns a tuple with the Uptime field value // and a boolean to check if the value has been set. -func (o *SetProjectState) GetUptimeOk() (*int32, bool) { +func (o *UpdateWorkspaceMetadataDTO) GetUptimeOk() (*int32, bool) { if o == nil { return nil, false } @@ -97,11 +97,11 @@ func (o *SetProjectState) GetUptimeOk() (*int32, bool) { } // SetUptime sets field value -func (o *SetProjectState) SetUptime(v int32) { +func (o *UpdateWorkspaceMetadataDTO) SetUptime(v int32) { o.Uptime = v } -func (o SetProjectState) MarshalJSON() ([]byte, error) { +func (o UpdateWorkspaceMetadataDTO) MarshalJSON() ([]byte, error) { toSerialize, err := o.ToMap() if err != nil { return []byte{}, err @@ -109,7 +109,7 @@ func (o SetProjectState) MarshalJSON() ([]byte, error) { return json.Marshal(toSerialize) } -func (o SetProjectState) ToMap() (map[string]interface{}, error) { +func (o UpdateWorkspaceMetadataDTO) ToMap() (map[string]interface{}, error) { toSerialize := map[string]interface{}{} if !IsNil(o.GitStatus) { toSerialize["gitStatus"] = o.GitStatus @@ -118,7 +118,7 @@ func (o SetProjectState) ToMap() (map[string]interface{}, error) { return toSerialize, nil } -func (o *SetProjectState) UnmarshalJSON(data []byte) (err error) { +func (o *UpdateWorkspaceMetadataDTO) UnmarshalJSON(data []byte) (err error) { // This validates that all required properties are included in the JSON object // by unmarshalling the object into a generic map with string keys and checking // that every required field exists as a key in the generic map. @@ -140,53 +140,53 @@ func (o *SetProjectState) UnmarshalJSON(data []byte) (err error) { } } - varSetProjectState := _SetProjectState{} + varUpdateWorkspaceMetadataDTO := _UpdateWorkspaceMetadataDTO{} decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() - err = decoder.Decode(&varSetProjectState) + err = decoder.Decode(&varUpdateWorkspaceMetadataDTO) if err != nil { return err } - *o = SetProjectState(varSetProjectState) + *o = UpdateWorkspaceMetadataDTO(varUpdateWorkspaceMetadataDTO) return err } -type NullableSetProjectState struct { - value *SetProjectState +type NullableUpdateWorkspaceMetadataDTO struct { + value *UpdateWorkspaceMetadataDTO isSet bool } -func (v NullableSetProjectState) Get() *SetProjectState { +func (v NullableUpdateWorkspaceMetadataDTO) Get() *UpdateWorkspaceMetadataDTO { return v.value } -func (v *NullableSetProjectState) Set(val *SetProjectState) { +func (v *NullableUpdateWorkspaceMetadataDTO) Set(val *UpdateWorkspaceMetadataDTO) { v.value = val v.isSet = true } -func (v NullableSetProjectState) IsSet() bool { +func (v NullableUpdateWorkspaceMetadataDTO) IsSet() bool { return v.isSet } -func (v *NullableSetProjectState) Unset() { +func (v *NullableUpdateWorkspaceMetadataDTO) Unset() { v.value = nil v.isSet = false } -func NewNullableSetProjectState(val *SetProjectState) *NullableSetProjectState { - return &NullableSetProjectState{value: val, isSet: true} +func NewNullableUpdateWorkspaceMetadataDTO(val *UpdateWorkspaceMetadataDTO) *NullableUpdateWorkspaceMetadataDTO { + return &NullableUpdateWorkspaceMetadataDTO{value: val, isSet: true} } -func (v NullableSetProjectState) MarshalJSON() ([]byte, error) { +func (v NullableUpdateWorkspaceMetadataDTO) MarshalJSON() ([]byte, error) { return json.Marshal(v.value) } -func (v *NullableSetProjectState) UnmarshalJSON(src []byte) error { +func (v *NullableUpdateWorkspaceMetadataDTO) UnmarshalJSON(src []byte) error { v.isSet = true return json.Unmarshal(src, &v.value) } diff --git a/pkg/apiclient/model_update_workspace_provider_metadata_dto.go b/pkg/apiclient/model_update_workspace_provider_metadata_dto.go new file mode 100644 index 0000000000..f17f720aac --- /dev/null +++ b/pkg/apiclient/model_update_workspace_provider_metadata_dto.go @@ -0,0 +1,156 @@ +/* +Daytona Server API + +Daytona Server API + +API version: v0.0.0-dev +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package apiclient + +import ( + "bytes" + "encoding/json" + "fmt" +) + +// checks if the UpdateWorkspaceProviderMetadataDTO type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &UpdateWorkspaceProviderMetadataDTO{} + +// UpdateWorkspaceProviderMetadataDTO struct for UpdateWorkspaceProviderMetadataDTO +type UpdateWorkspaceProviderMetadataDTO struct { + Metadata string `json:"metadata"` +} + +type _UpdateWorkspaceProviderMetadataDTO UpdateWorkspaceProviderMetadataDTO + +// NewUpdateWorkspaceProviderMetadataDTO instantiates a new UpdateWorkspaceProviderMetadataDTO object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewUpdateWorkspaceProviderMetadataDTO(metadata string) *UpdateWorkspaceProviderMetadataDTO { + this := UpdateWorkspaceProviderMetadataDTO{} + this.Metadata = metadata + return &this +} + +// NewUpdateWorkspaceProviderMetadataDTOWithDefaults instantiates a new UpdateWorkspaceProviderMetadataDTO object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewUpdateWorkspaceProviderMetadataDTOWithDefaults() *UpdateWorkspaceProviderMetadataDTO { + this := UpdateWorkspaceProviderMetadataDTO{} + return &this +} + +// GetMetadata returns the Metadata field value +func (o *UpdateWorkspaceProviderMetadataDTO) GetMetadata() string { + if o == nil { + var ret string + return ret + } + + return o.Metadata +} + +// GetMetadataOk returns a tuple with the Metadata field value +// and a boolean to check if the value has been set. +func (o *UpdateWorkspaceProviderMetadataDTO) GetMetadataOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Metadata, true +} + +// SetMetadata sets field value +func (o *UpdateWorkspaceProviderMetadataDTO) SetMetadata(v string) { + o.Metadata = v +} + +func (o UpdateWorkspaceProviderMetadataDTO) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o UpdateWorkspaceProviderMetadataDTO) ToMap() (map[string]interface{}, error) { + toSerialize := map[string]interface{}{} + toSerialize["metadata"] = o.Metadata + return toSerialize, nil +} + +func (o *UpdateWorkspaceProviderMetadataDTO) UnmarshalJSON(data []byte) (err error) { + // This validates that all required properties are included in the JSON object + // by unmarshalling the object into a generic map with string keys and checking + // that every required field exists as a key in the generic map. + requiredProperties := []string{ + "metadata", + } + + allProperties := make(map[string]interface{}) + + err = json.Unmarshal(data, &allProperties) + + if err != nil { + return err + } + + for _, requiredProperty := range requiredProperties { + if _, exists := allProperties[requiredProperty]; !exists { + return fmt.Errorf("no value given for required property %v", requiredProperty) + } + } + + varUpdateWorkspaceProviderMetadataDTO := _UpdateWorkspaceProviderMetadataDTO{} + + decoder := json.NewDecoder(bytes.NewReader(data)) + decoder.DisallowUnknownFields() + err = decoder.Decode(&varUpdateWorkspaceProviderMetadataDTO) + + if err != nil { + return err + } + + *o = UpdateWorkspaceProviderMetadataDTO(varUpdateWorkspaceProviderMetadataDTO) + + return err +} + +type NullableUpdateWorkspaceProviderMetadataDTO struct { + value *UpdateWorkspaceProviderMetadataDTO + isSet bool +} + +func (v NullableUpdateWorkspaceProviderMetadataDTO) Get() *UpdateWorkspaceProviderMetadataDTO { + return v.value +} + +func (v *NullableUpdateWorkspaceProviderMetadataDTO) Set(val *UpdateWorkspaceProviderMetadataDTO) { + v.value = val + v.isSet = true +} + +func (v NullableUpdateWorkspaceProviderMetadataDTO) IsSet() bool { + return v.isSet +} + +func (v *NullableUpdateWorkspaceProviderMetadataDTO) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableUpdateWorkspaceProviderMetadataDTO(val *UpdateWorkspaceProviderMetadataDTO) *NullableUpdateWorkspaceProviderMetadataDTO { + return &NullableUpdateWorkspaceProviderMetadataDTO{value: val, isSet: true} +} + +func (v NullableUpdateWorkspaceProviderMetadataDTO) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableUpdateWorkspaceProviderMetadataDTO) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/pkg/apiclient/model_workspace.go b/pkg/apiclient/model_workspace.go index be046fceb2..c2d580b0c5 100644 --- a/pkg/apiclient/model_workspace.go +++ b/pkg/apiclient/model_workspace.go @@ -21,10 +21,22 @@ var _ MappedNullable = &Workspace{} // Workspace struct for Workspace type Workspace struct { - Id string `json:"id"` - Name string `json:"name"` - Projects []Project `json:"projects"` - Target string `json:"target"` + ApiKey string `json:"apiKey"` + BuildConfig *BuildConfig `json:"buildConfig,omitempty"` + EnvVars map[string]string `json:"envVars"` + GitProviderConfigId *string `json:"gitProviderConfigId,omitempty"` + Id string `json:"id"` + Image string `json:"image"` + Labels map[string]string `json:"labels"` + LastJob *Job `json:"lastJob,omitempty"` + LastJobId *string `json:"lastJobId,omitempty"` + Metadata *WorkspaceMetadata `json:"metadata,omitempty"` + Name string `json:"name"` + ProviderMetadata *string `json:"providerMetadata,omitempty"` + Repository GitRepository `json:"repository"` + Target Target `json:"target"` + TargetId string `json:"targetId"` + User string `json:"user"` } type _Workspace Workspace @@ -33,12 +45,18 @@ type _Workspace Workspace // This constructor will assign default values to properties that have it defined, // and makes sure properties required by API are set, but the set of arguments // will change when the set of required properties is changed -func NewWorkspace(id string, name string, projects []Project, target string) *Workspace { +func NewWorkspace(apiKey string, envVars map[string]string, id string, image string, labels map[string]string, name string, repository GitRepository, target Target, targetId string, user string) *Workspace { this := Workspace{} + this.ApiKey = apiKey + this.EnvVars = envVars this.Id = id + this.Image = image + this.Labels = labels this.Name = name - this.Projects = projects + this.Repository = repository this.Target = target + this.TargetId = targetId + this.User = user return &this } @@ -50,6 +68,118 @@ func NewWorkspaceWithDefaults() *Workspace { return &this } +// GetApiKey returns the ApiKey field value +func (o *Workspace) GetApiKey() string { + if o == nil { + var ret string + return ret + } + + return o.ApiKey +} + +// GetApiKeyOk returns a tuple with the ApiKey field value +// and a boolean to check if the value has been set. +func (o *Workspace) GetApiKeyOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.ApiKey, true +} + +// SetApiKey sets field value +func (o *Workspace) SetApiKey(v string) { + o.ApiKey = v +} + +// GetBuildConfig returns the BuildConfig field value if set, zero value otherwise. +func (o *Workspace) GetBuildConfig() BuildConfig { + if o == nil || IsNil(o.BuildConfig) { + var ret BuildConfig + return ret + } + return *o.BuildConfig +} + +// GetBuildConfigOk returns a tuple with the BuildConfig field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *Workspace) GetBuildConfigOk() (*BuildConfig, bool) { + if o == nil || IsNil(o.BuildConfig) { + return nil, false + } + return o.BuildConfig, true +} + +// HasBuildConfig returns a boolean if a field has been set. +func (o *Workspace) HasBuildConfig() bool { + if o != nil && !IsNil(o.BuildConfig) { + return true + } + + return false +} + +// SetBuildConfig gets a reference to the given BuildConfig and assigns it to the BuildConfig field. +func (o *Workspace) SetBuildConfig(v BuildConfig) { + o.BuildConfig = &v +} + +// GetEnvVars returns the EnvVars field value +func (o *Workspace) GetEnvVars() map[string]string { + if o == nil { + var ret map[string]string + return ret + } + + return o.EnvVars +} + +// GetEnvVarsOk returns a tuple with the EnvVars field value +// and a boolean to check if the value has been set. +func (o *Workspace) GetEnvVarsOk() (*map[string]string, bool) { + if o == nil { + return nil, false + } + return &o.EnvVars, true +} + +// SetEnvVars sets field value +func (o *Workspace) SetEnvVars(v map[string]string) { + o.EnvVars = v +} + +// GetGitProviderConfigId returns the GitProviderConfigId field value if set, zero value otherwise. +func (o *Workspace) GetGitProviderConfigId() string { + if o == nil || IsNil(o.GitProviderConfigId) { + var ret string + return ret + } + return *o.GitProviderConfigId +} + +// GetGitProviderConfigIdOk returns a tuple with the GitProviderConfigId field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *Workspace) GetGitProviderConfigIdOk() (*string, bool) { + if o == nil || IsNil(o.GitProviderConfigId) { + return nil, false + } + return o.GitProviderConfigId, true +} + +// HasGitProviderConfigId returns a boolean if a field has been set. +func (o *Workspace) HasGitProviderConfigId() bool { + if o != nil && !IsNil(o.GitProviderConfigId) { + return true + } + + return false +} + +// SetGitProviderConfigId gets a reference to the given string and assigns it to the GitProviderConfigId field. +func (o *Workspace) SetGitProviderConfigId(v string) { + o.GitProviderConfigId = &v +} + // GetId returns the Id field value func (o *Workspace) GetId() string { if o == nil { @@ -74,6 +204,150 @@ func (o *Workspace) SetId(v string) { o.Id = v } +// GetImage returns the Image field value +func (o *Workspace) GetImage() string { + if o == nil { + var ret string + return ret + } + + return o.Image +} + +// GetImageOk returns a tuple with the Image field value +// and a boolean to check if the value has been set. +func (o *Workspace) GetImageOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Image, true +} + +// SetImage sets field value +func (o *Workspace) SetImage(v string) { + o.Image = v +} + +// GetLabels returns the Labels field value +func (o *Workspace) GetLabels() map[string]string { + if o == nil { + var ret map[string]string + return ret + } + + return o.Labels +} + +// GetLabelsOk returns a tuple with the Labels field value +// and a boolean to check if the value has been set. +func (o *Workspace) GetLabelsOk() (*map[string]string, bool) { + if o == nil { + return nil, false + } + return &o.Labels, true +} + +// SetLabels sets field value +func (o *Workspace) SetLabels(v map[string]string) { + o.Labels = v +} + +// GetLastJob returns the LastJob field value if set, zero value otherwise. +func (o *Workspace) GetLastJob() Job { + if o == nil || IsNil(o.LastJob) { + var ret Job + return ret + } + return *o.LastJob +} + +// GetLastJobOk returns a tuple with the LastJob field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *Workspace) GetLastJobOk() (*Job, bool) { + if o == nil || IsNil(o.LastJob) { + return nil, false + } + return o.LastJob, true +} + +// HasLastJob returns a boolean if a field has been set. +func (o *Workspace) HasLastJob() bool { + if o != nil && !IsNil(o.LastJob) { + return true + } + + return false +} + +// SetLastJob gets a reference to the given Job and assigns it to the LastJob field. +func (o *Workspace) SetLastJob(v Job) { + o.LastJob = &v +} + +// GetLastJobId returns the LastJobId field value if set, zero value otherwise. +func (o *Workspace) GetLastJobId() string { + if o == nil || IsNil(o.LastJobId) { + var ret string + return ret + } + return *o.LastJobId +} + +// GetLastJobIdOk returns a tuple with the LastJobId field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *Workspace) GetLastJobIdOk() (*string, bool) { + if o == nil || IsNil(o.LastJobId) { + return nil, false + } + return o.LastJobId, true +} + +// HasLastJobId returns a boolean if a field has been set. +func (o *Workspace) HasLastJobId() bool { + if o != nil && !IsNil(o.LastJobId) { + return true + } + + return false +} + +// SetLastJobId gets a reference to the given string and assigns it to the LastJobId field. +func (o *Workspace) SetLastJobId(v string) { + o.LastJobId = &v +} + +// GetMetadata returns the Metadata field value if set, zero value otherwise. +func (o *Workspace) GetMetadata() WorkspaceMetadata { + if o == nil || IsNil(o.Metadata) { + var ret WorkspaceMetadata + return ret + } + return *o.Metadata +} + +// GetMetadataOk returns a tuple with the Metadata field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *Workspace) GetMetadataOk() (*WorkspaceMetadata, bool) { + if o == nil || IsNil(o.Metadata) { + return nil, false + } + return o.Metadata, true +} + +// HasMetadata returns a boolean if a field has been set. +func (o *Workspace) HasMetadata() bool { + if o != nil && !IsNil(o.Metadata) { + return true + } + + return false +} + +// SetMetadata gets a reference to the given WorkspaceMetadata and assigns it to the Metadata field. +func (o *Workspace) SetMetadata(v WorkspaceMetadata) { + o.Metadata = &v +} + // GetName returns the Name field value func (o *Workspace) GetName() string { if o == nil { @@ -98,34 +372,66 @@ func (o *Workspace) SetName(v string) { o.Name = v } -// GetProjects returns the Projects field value -func (o *Workspace) GetProjects() []Project { +// GetProviderMetadata returns the ProviderMetadata field value if set, zero value otherwise. +func (o *Workspace) GetProviderMetadata() string { + if o == nil || IsNil(o.ProviderMetadata) { + var ret string + return ret + } + return *o.ProviderMetadata +} + +// GetProviderMetadataOk returns a tuple with the ProviderMetadata field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *Workspace) GetProviderMetadataOk() (*string, bool) { + if o == nil || IsNil(o.ProviderMetadata) { + return nil, false + } + return o.ProviderMetadata, true +} + +// HasProviderMetadata returns a boolean if a field has been set. +func (o *Workspace) HasProviderMetadata() bool { + if o != nil && !IsNil(o.ProviderMetadata) { + return true + } + + return false +} + +// SetProviderMetadata gets a reference to the given string and assigns it to the ProviderMetadata field. +func (o *Workspace) SetProviderMetadata(v string) { + o.ProviderMetadata = &v +} + +// GetRepository returns the Repository field value +func (o *Workspace) GetRepository() GitRepository { if o == nil { - var ret []Project + var ret GitRepository return ret } - return o.Projects + return o.Repository } -// GetProjectsOk returns a tuple with the Projects field value +// GetRepositoryOk returns a tuple with the Repository field value // and a boolean to check if the value has been set. -func (o *Workspace) GetProjectsOk() ([]Project, bool) { +func (o *Workspace) GetRepositoryOk() (*GitRepository, bool) { if o == nil { return nil, false } - return o.Projects, true + return &o.Repository, true } -// SetProjects sets field value -func (o *Workspace) SetProjects(v []Project) { - o.Projects = v +// SetRepository sets field value +func (o *Workspace) SetRepository(v GitRepository) { + o.Repository = v } // GetTarget returns the Target field value -func (o *Workspace) GetTarget() string { +func (o *Workspace) GetTarget() Target { if o == nil { - var ret string + var ret Target return ret } @@ -134,7 +440,7 @@ func (o *Workspace) GetTarget() string { // GetTargetOk returns a tuple with the Target field value // and a boolean to check if the value has been set. -func (o *Workspace) GetTargetOk() (*string, bool) { +func (o *Workspace) GetTargetOk() (*Target, bool) { if o == nil { return nil, false } @@ -142,10 +448,58 @@ func (o *Workspace) GetTargetOk() (*string, bool) { } // SetTarget sets field value -func (o *Workspace) SetTarget(v string) { +func (o *Workspace) SetTarget(v Target) { o.Target = v } +// GetTargetId returns the TargetId field value +func (o *Workspace) GetTargetId() string { + if o == nil { + var ret string + return ret + } + + return o.TargetId +} + +// GetTargetIdOk returns a tuple with the TargetId field value +// and a boolean to check if the value has been set. +func (o *Workspace) GetTargetIdOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.TargetId, true +} + +// SetTargetId sets field value +func (o *Workspace) SetTargetId(v string) { + o.TargetId = v +} + +// GetUser returns the User field value +func (o *Workspace) GetUser() string { + if o == nil { + var ret string + return ret + } + + return o.User +} + +// GetUserOk returns a tuple with the User field value +// and a boolean to check if the value has been set. +func (o *Workspace) GetUserOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.User, true +} + +// SetUser sets field value +func (o *Workspace) SetUser(v string) { + o.User = v +} + func (o Workspace) MarshalJSON() ([]byte, error) { toSerialize, err := o.ToMap() if err != nil { @@ -156,10 +510,34 @@ func (o Workspace) MarshalJSON() ([]byte, error) { func (o Workspace) ToMap() (map[string]interface{}, error) { toSerialize := map[string]interface{}{} + toSerialize["apiKey"] = o.ApiKey + if !IsNil(o.BuildConfig) { + toSerialize["buildConfig"] = o.BuildConfig + } + toSerialize["envVars"] = o.EnvVars + if !IsNil(o.GitProviderConfigId) { + toSerialize["gitProviderConfigId"] = o.GitProviderConfigId + } toSerialize["id"] = o.Id + toSerialize["image"] = o.Image + toSerialize["labels"] = o.Labels + if !IsNil(o.LastJob) { + toSerialize["lastJob"] = o.LastJob + } + if !IsNil(o.LastJobId) { + toSerialize["lastJobId"] = o.LastJobId + } + if !IsNil(o.Metadata) { + toSerialize["metadata"] = o.Metadata + } toSerialize["name"] = o.Name - toSerialize["projects"] = o.Projects + if !IsNil(o.ProviderMetadata) { + toSerialize["providerMetadata"] = o.ProviderMetadata + } + toSerialize["repository"] = o.Repository toSerialize["target"] = o.Target + toSerialize["targetId"] = o.TargetId + toSerialize["user"] = o.User return toSerialize, nil } @@ -168,10 +546,16 @@ func (o *Workspace) UnmarshalJSON(data []byte) (err error) { // by unmarshalling the object into a generic map with string keys and checking // that every required field exists as a key in the generic map. requiredProperties := []string{ + "apiKey", + "envVars", "id", + "image", + "labels", "name", - "projects", + "repository", "target", + "targetId", + "user", } allProperties := make(map[string]interface{}) diff --git a/pkg/apiclient/model_project_dir_response.go b/pkg/apiclient/model_workspace_dir_response.go similarity index 52% rename from pkg/apiclient/model_project_dir_response.go rename to pkg/apiclient/model_workspace_dir_response.go index 142707bf66..9ce87fb0b7 100644 --- a/pkg/apiclient/model_project_dir_response.go +++ b/pkg/apiclient/model_workspace_dir_response.go @@ -14,33 +14,33 @@ import ( "encoding/json" ) -// checks if the ProjectDirResponse type satisfies the MappedNullable interface at compile time -var _ MappedNullable = &ProjectDirResponse{} +// checks if the WorkspaceDirResponse type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &WorkspaceDirResponse{} -// ProjectDirResponse struct for ProjectDirResponse -type ProjectDirResponse struct { +// WorkspaceDirResponse struct for WorkspaceDirResponse +type WorkspaceDirResponse struct { Dir *string `json:"dir,omitempty"` } -// NewProjectDirResponse instantiates a new ProjectDirResponse object +// NewWorkspaceDirResponse instantiates a new WorkspaceDirResponse object // This constructor will assign default values to properties that have it defined, // and makes sure properties required by API are set, but the set of arguments // will change when the set of required properties is changed -func NewProjectDirResponse() *ProjectDirResponse { - this := ProjectDirResponse{} +func NewWorkspaceDirResponse() *WorkspaceDirResponse { + this := WorkspaceDirResponse{} return &this } -// NewProjectDirResponseWithDefaults instantiates a new ProjectDirResponse object +// NewWorkspaceDirResponseWithDefaults instantiates a new WorkspaceDirResponse object // This constructor will only assign default values to properties that have it defined, // but it doesn't guarantee that properties required by API are set -func NewProjectDirResponseWithDefaults() *ProjectDirResponse { - this := ProjectDirResponse{} +func NewWorkspaceDirResponseWithDefaults() *WorkspaceDirResponse { + this := WorkspaceDirResponse{} return &this } // GetDir returns the Dir field value if set, zero value otherwise. -func (o *ProjectDirResponse) GetDir() string { +func (o *WorkspaceDirResponse) GetDir() string { if o == nil || IsNil(o.Dir) { var ret string return ret @@ -50,7 +50,7 @@ func (o *ProjectDirResponse) GetDir() string { // GetDirOk returns a tuple with the Dir field value if set, nil otherwise // and a boolean to check if the value has been set. -func (o *ProjectDirResponse) GetDirOk() (*string, bool) { +func (o *WorkspaceDirResponse) GetDirOk() (*string, bool) { if o == nil || IsNil(o.Dir) { return nil, false } @@ -58,7 +58,7 @@ func (o *ProjectDirResponse) GetDirOk() (*string, bool) { } // HasDir returns a boolean if a field has been set. -func (o *ProjectDirResponse) HasDir() bool { +func (o *WorkspaceDirResponse) HasDir() bool { if o != nil && !IsNil(o.Dir) { return true } @@ -67,11 +67,11 @@ func (o *ProjectDirResponse) HasDir() bool { } // SetDir gets a reference to the given string and assigns it to the Dir field. -func (o *ProjectDirResponse) SetDir(v string) { +func (o *WorkspaceDirResponse) SetDir(v string) { o.Dir = &v } -func (o ProjectDirResponse) MarshalJSON() ([]byte, error) { +func (o WorkspaceDirResponse) MarshalJSON() ([]byte, error) { toSerialize, err := o.ToMap() if err != nil { return []byte{}, err @@ -79,7 +79,7 @@ func (o ProjectDirResponse) MarshalJSON() ([]byte, error) { return json.Marshal(toSerialize) } -func (o ProjectDirResponse) ToMap() (map[string]interface{}, error) { +func (o WorkspaceDirResponse) ToMap() (map[string]interface{}, error) { toSerialize := map[string]interface{}{} if !IsNil(o.Dir) { toSerialize["dir"] = o.Dir @@ -87,38 +87,38 @@ func (o ProjectDirResponse) ToMap() (map[string]interface{}, error) { return toSerialize, nil } -type NullableProjectDirResponse struct { - value *ProjectDirResponse +type NullableWorkspaceDirResponse struct { + value *WorkspaceDirResponse isSet bool } -func (v NullableProjectDirResponse) Get() *ProjectDirResponse { +func (v NullableWorkspaceDirResponse) Get() *WorkspaceDirResponse { return v.value } -func (v *NullableProjectDirResponse) Set(val *ProjectDirResponse) { +func (v *NullableWorkspaceDirResponse) Set(val *WorkspaceDirResponse) { v.value = val v.isSet = true } -func (v NullableProjectDirResponse) IsSet() bool { +func (v NullableWorkspaceDirResponse) IsSet() bool { return v.isSet } -func (v *NullableProjectDirResponse) Unset() { +func (v *NullableWorkspaceDirResponse) Unset() { v.value = nil v.isSet = false } -func NewNullableProjectDirResponse(val *ProjectDirResponse) *NullableProjectDirResponse { - return &NullableProjectDirResponse{value: val, isSet: true} +func NewNullableWorkspaceDirResponse(val *WorkspaceDirResponse) *NullableWorkspaceDirResponse { + return &NullableWorkspaceDirResponse{value: val, isSet: true} } -func (v NullableProjectDirResponse) MarshalJSON() ([]byte, error) { +func (v NullableWorkspaceDirResponse) MarshalJSON() ([]byte, error) { return json.Marshal(v.value) } -func (v *NullableProjectDirResponse) UnmarshalJSON(src []byte) error { +func (v *NullableWorkspaceDirResponse) UnmarshalJSON(src []byte) error { v.isSet = true return json.Unmarshal(src, &v.value) } diff --git a/pkg/apiclient/model_workspace_dto.go b/pkg/apiclient/model_workspace_dto.go index c1c33251f9..f19881e444 100644 --- a/pkg/apiclient/model_workspace_dto.go +++ b/pkg/apiclient/model_workspace_dto.go @@ -21,11 +21,23 @@ var _ MappedNullable = &WorkspaceDTO{} // WorkspaceDTO struct for WorkspaceDTO type WorkspaceDTO struct { - Id string `json:"id"` - Info *WorkspaceInfo `json:"info,omitempty"` - Name string `json:"name"` - Projects []Project `json:"projects"` - Target string `json:"target"` + ApiKey string `json:"apiKey"` + BuildConfig *BuildConfig `json:"buildConfig,omitempty"` + EnvVars map[string]string `json:"envVars"` + GitProviderConfigId *string `json:"gitProviderConfigId,omitempty"` + Id string `json:"id"` + Image string `json:"image"` + Labels map[string]string `json:"labels"` + LastJob *Job `json:"lastJob,omitempty"` + LastJobId *string `json:"lastJobId,omitempty"` + Metadata *WorkspaceMetadata `json:"metadata,omitempty"` + Name string `json:"name"` + ProviderMetadata *string `json:"providerMetadata,omitempty"` + Repository GitRepository `json:"repository"` + State ResourceState `json:"state"` + Target Target `json:"target"` + TargetId string `json:"targetId"` + User string `json:"user"` } type _WorkspaceDTO WorkspaceDTO @@ -34,12 +46,19 @@ type _WorkspaceDTO WorkspaceDTO // This constructor will assign default values to properties that have it defined, // and makes sure properties required by API are set, but the set of arguments // will change when the set of required properties is changed -func NewWorkspaceDTO(id string, name string, projects []Project, target string) *WorkspaceDTO { +func NewWorkspaceDTO(apiKey string, envVars map[string]string, id string, image string, labels map[string]string, name string, repository GitRepository, state ResourceState, target Target, targetId string, user string) *WorkspaceDTO { this := WorkspaceDTO{} + this.ApiKey = apiKey + this.EnvVars = envVars this.Id = id + this.Image = image + this.Labels = labels this.Name = name - this.Projects = projects + this.Repository = repository + this.State = state this.Target = target + this.TargetId = targetId + this.User = user return &this } @@ -51,6 +70,118 @@ func NewWorkspaceDTOWithDefaults() *WorkspaceDTO { return &this } +// GetApiKey returns the ApiKey field value +func (o *WorkspaceDTO) GetApiKey() string { + if o == nil { + var ret string + return ret + } + + return o.ApiKey +} + +// GetApiKeyOk returns a tuple with the ApiKey field value +// and a boolean to check if the value has been set. +func (o *WorkspaceDTO) GetApiKeyOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.ApiKey, true +} + +// SetApiKey sets field value +func (o *WorkspaceDTO) SetApiKey(v string) { + o.ApiKey = v +} + +// GetBuildConfig returns the BuildConfig field value if set, zero value otherwise. +func (o *WorkspaceDTO) GetBuildConfig() BuildConfig { + if o == nil || IsNil(o.BuildConfig) { + var ret BuildConfig + return ret + } + return *o.BuildConfig +} + +// GetBuildConfigOk returns a tuple with the BuildConfig field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *WorkspaceDTO) GetBuildConfigOk() (*BuildConfig, bool) { + if o == nil || IsNil(o.BuildConfig) { + return nil, false + } + return o.BuildConfig, true +} + +// HasBuildConfig returns a boolean if a field has been set. +func (o *WorkspaceDTO) HasBuildConfig() bool { + if o != nil && !IsNil(o.BuildConfig) { + return true + } + + return false +} + +// SetBuildConfig gets a reference to the given BuildConfig and assigns it to the BuildConfig field. +func (o *WorkspaceDTO) SetBuildConfig(v BuildConfig) { + o.BuildConfig = &v +} + +// GetEnvVars returns the EnvVars field value +func (o *WorkspaceDTO) GetEnvVars() map[string]string { + if o == nil { + var ret map[string]string + return ret + } + + return o.EnvVars +} + +// GetEnvVarsOk returns a tuple with the EnvVars field value +// and a boolean to check if the value has been set. +func (o *WorkspaceDTO) GetEnvVarsOk() (*map[string]string, bool) { + if o == nil { + return nil, false + } + return &o.EnvVars, true +} + +// SetEnvVars sets field value +func (o *WorkspaceDTO) SetEnvVars(v map[string]string) { + o.EnvVars = v +} + +// GetGitProviderConfigId returns the GitProviderConfigId field value if set, zero value otherwise. +func (o *WorkspaceDTO) GetGitProviderConfigId() string { + if o == nil || IsNil(o.GitProviderConfigId) { + var ret string + return ret + } + return *o.GitProviderConfigId +} + +// GetGitProviderConfigIdOk returns a tuple with the GitProviderConfigId field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *WorkspaceDTO) GetGitProviderConfigIdOk() (*string, bool) { + if o == nil || IsNil(o.GitProviderConfigId) { + return nil, false + } + return o.GitProviderConfigId, true +} + +// HasGitProviderConfigId returns a boolean if a field has been set. +func (o *WorkspaceDTO) HasGitProviderConfigId() bool { + if o != nil && !IsNil(o.GitProviderConfigId) { + return true + } + + return false +} + +// SetGitProviderConfigId gets a reference to the given string and assigns it to the GitProviderConfigId field. +func (o *WorkspaceDTO) SetGitProviderConfigId(v string) { + o.GitProviderConfigId = &v +} + // GetId returns the Id field value func (o *WorkspaceDTO) GetId() string { if o == nil { @@ -75,36 +206,148 @@ func (o *WorkspaceDTO) SetId(v string) { o.Id = v } -// GetInfo returns the Info field value if set, zero value otherwise. -func (o *WorkspaceDTO) GetInfo() WorkspaceInfo { - if o == nil || IsNil(o.Info) { - var ret WorkspaceInfo +// GetImage returns the Image field value +func (o *WorkspaceDTO) GetImage() string { + if o == nil { + var ret string + return ret + } + + return o.Image +} + +// GetImageOk returns a tuple with the Image field value +// and a boolean to check if the value has been set. +func (o *WorkspaceDTO) GetImageOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Image, true +} + +// SetImage sets field value +func (o *WorkspaceDTO) SetImage(v string) { + o.Image = v +} + +// GetLabels returns the Labels field value +func (o *WorkspaceDTO) GetLabels() map[string]string { + if o == nil { + var ret map[string]string + return ret + } + + return o.Labels +} + +// GetLabelsOk returns a tuple with the Labels field value +// and a boolean to check if the value has been set. +func (o *WorkspaceDTO) GetLabelsOk() (*map[string]string, bool) { + if o == nil { + return nil, false + } + return &o.Labels, true +} + +// SetLabels sets field value +func (o *WorkspaceDTO) SetLabels(v map[string]string) { + o.Labels = v +} + +// GetLastJob returns the LastJob field value if set, zero value otherwise. +func (o *WorkspaceDTO) GetLastJob() Job { + if o == nil || IsNil(o.LastJob) { + var ret Job + return ret + } + return *o.LastJob +} + +// GetLastJobOk returns a tuple with the LastJob field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *WorkspaceDTO) GetLastJobOk() (*Job, bool) { + if o == nil || IsNil(o.LastJob) { + return nil, false + } + return o.LastJob, true +} + +// HasLastJob returns a boolean if a field has been set. +func (o *WorkspaceDTO) HasLastJob() bool { + if o != nil && !IsNil(o.LastJob) { + return true + } + + return false +} + +// SetLastJob gets a reference to the given Job and assigns it to the LastJob field. +func (o *WorkspaceDTO) SetLastJob(v Job) { + o.LastJob = &v +} + +// GetLastJobId returns the LastJobId field value if set, zero value otherwise. +func (o *WorkspaceDTO) GetLastJobId() string { + if o == nil || IsNil(o.LastJobId) { + var ret string return ret } - return *o.Info + return *o.LastJobId } -// GetInfoOk returns a tuple with the Info field value if set, nil otherwise +// GetLastJobIdOk returns a tuple with the LastJobId field value if set, nil otherwise // and a boolean to check if the value has been set. -func (o *WorkspaceDTO) GetInfoOk() (*WorkspaceInfo, bool) { - if o == nil || IsNil(o.Info) { +func (o *WorkspaceDTO) GetLastJobIdOk() (*string, bool) { + if o == nil || IsNil(o.LastJobId) { return nil, false } - return o.Info, true + return o.LastJobId, true } -// HasInfo returns a boolean if a field has been set. -func (o *WorkspaceDTO) HasInfo() bool { - if o != nil && !IsNil(o.Info) { +// HasLastJobId returns a boolean if a field has been set. +func (o *WorkspaceDTO) HasLastJobId() bool { + if o != nil && !IsNil(o.LastJobId) { return true } return false } -// SetInfo gets a reference to the given WorkspaceInfo and assigns it to the Info field. -func (o *WorkspaceDTO) SetInfo(v WorkspaceInfo) { - o.Info = &v +// SetLastJobId gets a reference to the given string and assigns it to the LastJobId field. +func (o *WorkspaceDTO) SetLastJobId(v string) { + o.LastJobId = &v +} + +// GetMetadata returns the Metadata field value if set, zero value otherwise. +func (o *WorkspaceDTO) GetMetadata() WorkspaceMetadata { + if o == nil || IsNil(o.Metadata) { + var ret WorkspaceMetadata + return ret + } + return *o.Metadata +} + +// GetMetadataOk returns a tuple with the Metadata field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *WorkspaceDTO) GetMetadataOk() (*WorkspaceMetadata, bool) { + if o == nil || IsNil(o.Metadata) { + return nil, false + } + return o.Metadata, true +} + +// HasMetadata returns a boolean if a field has been set. +func (o *WorkspaceDTO) HasMetadata() bool { + if o != nil && !IsNil(o.Metadata) { + return true + } + + return false +} + +// SetMetadata gets a reference to the given WorkspaceMetadata and assigns it to the Metadata field. +func (o *WorkspaceDTO) SetMetadata(v WorkspaceMetadata) { + o.Metadata = &v } // GetName returns the Name field value @@ -131,34 +374,90 @@ func (o *WorkspaceDTO) SetName(v string) { o.Name = v } -// GetProjects returns the Projects field value -func (o *WorkspaceDTO) GetProjects() []Project { +// GetProviderMetadata returns the ProviderMetadata field value if set, zero value otherwise. +func (o *WorkspaceDTO) GetProviderMetadata() string { + if o == nil || IsNil(o.ProviderMetadata) { + var ret string + return ret + } + return *o.ProviderMetadata +} + +// GetProviderMetadataOk returns a tuple with the ProviderMetadata field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *WorkspaceDTO) GetProviderMetadataOk() (*string, bool) { + if o == nil || IsNil(o.ProviderMetadata) { + return nil, false + } + return o.ProviderMetadata, true +} + +// HasProviderMetadata returns a boolean if a field has been set. +func (o *WorkspaceDTO) HasProviderMetadata() bool { + if o != nil && !IsNil(o.ProviderMetadata) { + return true + } + + return false +} + +// SetProviderMetadata gets a reference to the given string and assigns it to the ProviderMetadata field. +func (o *WorkspaceDTO) SetProviderMetadata(v string) { + o.ProviderMetadata = &v +} + +// GetRepository returns the Repository field value +func (o *WorkspaceDTO) GetRepository() GitRepository { + if o == nil { + var ret GitRepository + return ret + } + + return o.Repository +} + +// GetRepositoryOk returns a tuple with the Repository field value +// and a boolean to check if the value has been set. +func (o *WorkspaceDTO) GetRepositoryOk() (*GitRepository, bool) { + if o == nil { + return nil, false + } + return &o.Repository, true +} + +// SetRepository sets field value +func (o *WorkspaceDTO) SetRepository(v GitRepository) { + o.Repository = v +} + +// GetState returns the State field value +func (o *WorkspaceDTO) GetState() ResourceState { if o == nil { - var ret []Project + var ret ResourceState return ret } - return o.Projects + return o.State } -// GetProjectsOk returns a tuple with the Projects field value +// GetStateOk returns a tuple with the State field value // and a boolean to check if the value has been set. -func (o *WorkspaceDTO) GetProjectsOk() ([]Project, bool) { +func (o *WorkspaceDTO) GetStateOk() (*ResourceState, bool) { if o == nil { return nil, false } - return o.Projects, true + return &o.State, true } -// SetProjects sets field value -func (o *WorkspaceDTO) SetProjects(v []Project) { - o.Projects = v +// SetState sets field value +func (o *WorkspaceDTO) SetState(v ResourceState) { + o.State = v } // GetTarget returns the Target field value -func (o *WorkspaceDTO) GetTarget() string { +func (o *WorkspaceDTO) GetTarget() Target { if o == nil { - var ret string + var ret Target return ret } @@ -167,7 +466,7 @@ func (o *WorkspaceDTO) GetTarget() string { // GetTargetOk returns a tuple with the Target field value // and a boolean to check if the value has been set. -func (o *WorkspaceDTO) GetTargetOk() (*string, bool) { +func (o *WorkspaceDTO) GetTargetOk() (*Target, bool) { if o == nil { return nil, false } @@ -175,10 +474,58 @@ func (o *WorkspaceDTO) GetTargetOk() (*string, bool) { } // SetTarget sets field value -func (o *WorkspaceDTO) SetTarget(v string) { +func (o *WorkspaceDTO) SetTarget(v Target) { o.Target = v } +// GetTargetId returns the TargetId field value +func (o *WorkspaceDTO) GetTargetId() string { + if o == nil { + var ret string + return ret + } + + return o.TargetId +} + +// GetTargetIdOk returns a tuple with the TargetId field value +// and a boolean to check if the value has been set. +func (o *WorkspaceDTO) GetTargetIdOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.TargetId, true +} + +// SetTargetId sets field value +func (o *WorkspaceDTO) SetTargetId(v string) { + o.TargetId = v +} + +// GetUser returns the User field value +func (o *WorkspaceDTO) GetUser() string { + if o == nil { + var ret string + return ret + } + + return o.User +} + +// GetUserOk returns a tuple with the User field value +// and a boolean to check if the value has been set. +func (o *WorkspaceDTO) GetUserOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.User, true +} + +// SetUser sets field value +func (o *WorkspaceDTO) SetUser(v string) { + o.User = v +} + func (o WorkspaceDTO) MarshalJSON() ([]byte, error) { toSerialize, err := o.ToMap() if err != nil { @@ -189,13 +536,35 @@ func (o WorkspaceDTO) MarshalJSON() ([]byte, error) { func (o WorkspaceDTO) ToMap() (map[string]interface{}, error) { toSerialize := map[string]interface{}{} + toSerialize["apiKey"] = o.ApiKey + if !IsNil(o.BuildConfig) { + toSerialize["buildConfig"] = o.BuildConfig + } + toSerialize["envVars"] = o.EnvVars + if !IsNil(o.GitProviderConfigId) { + toSerialize["gitProviderConfigId"] = o.GitProviderConfigId + } toSerialize["id"] = o.Id - if !IsNil(o.Info) { - toSerialize["info"] = o.Info + toSerialize["image"] = o.Image + toSerialize["labels"] = o.Labels + if !IsNil(o.LastJob) { + toSerialize["lastJob"] = o.LastJob + } + if !IsNil(o.LastJobId) { + toSerialize["lastJobId"] = o.LastJobId + } + if !IsNil(o.Metadata) { + toSerialize["metadata"] = o.Metadata } toSerialize["name"] = o.Name - toSerialize["projects"] = o.Projects + if !IsNil(o.ProviderMetadata) { + toSerialize["providerMetadata"] = o.ProviderMetadata + } + toSerialize["repository"] = o.Repository + toSerialize["state"] = o.State toSerialize["target"] = o.Target + toSerialize["targetId"] = o.TargetId + toSerialize["user"] = o.User return toSerialize, nil } @@ -204,10 +573,17 @@ func (o *WorkspaceDTO) UnmarshalJSON(data []byte) (err error) { // by unmarshalling the object into a generic map with string keys and checking // that every required field exists as a key in the generic map. requiredProperties := []string{ + "apiKey", + "envVars", "id", + "image", + "labels", "name", - "projects", + "repository", + "state", "target", + "targetId", + "user", } allProperties := make(map[string]interface{}) diff --git a/pkg/apiclient/model_workspace_info.go b/pkg/apiclient/model_workspace_info.go deleted file mode 100644 index 7c7b22a6a3..0000000000 --- a/pkg/apiclient/model_workspace_info.go +++ /dev/null @@ -1,220 +0,0 @@ -/* -Daytona Server API - -Daytona Server API - -API version: v0.0.0-dev -*/ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package apiclient - -import ( - "bytes" - "encoding/json" - "fmt" -) - -// checks if the WorkspaceInfo type satisfies the MappedNullable interface at compile time -var _ MappedNullable = &WorkspaceInfo{} - -// WorkspaceInfo struct for WorkspaceInfo -type WorkspaceInfo struct { - Name string `json:"name"` - Projects []ProjectInfo `json:"projects"` - ProviderMetadata *string `json:"providerMetadata,omitempty"` -} - -type _WorkspaceInfo WorkspaceInfo - -// NewWorkspaceInfo instantiates a new WorkspaceInfo object -// This constructor will assign default values to properties that have it defined, -// and makes sure properties required by API are set, but the set of arguments -// will change when the set of required properties is changed -func NewWorkspaceInfo(name string, projects []ProjectInfo) *WorkspaceInfo { - this := WorkspaceInfo{} - this.Name = name - this.Projects = projects - return &this -} - -// NewWorkspaceInfoWithDefaults instantiates a new WorkspaceInfo object -// This constructor will only assign default values to properties that have it defined, -// but it doesn't guarantee that properties required by API are set -func NewWorkspaceInfoWithDefaults() *WorkspaceInfo { - this := WorkspaceInfo{} - return &this -} - -// GetName returns the Name field value -func (o *WorkspaceInfo) GetName() string { - if o == nil { - var ret string - return ret - } - - return o.Name -} - -// GetNameOk returns a tuple with the Name field value -// and a boolean to check if the value has been set. -func (o *WorkspaceInfo) GetNameOk() (*string, bool) { - if o == nil { - return nil, false - } - return &o.Name, true -} - -// SetName sets field value -func (o *WorkspaceInfo) SetName(v string) { - o.Name = v -} - -// GetProjects returns the Projects field value -func (o *WorkspaceInfo) GetProjects() []ProjectInfo { - if o == nil { - var ret []ProjectInfo - return ret - } - - return o.Projects -} - -// GetProjectsOk returns a tuple with the Projects field value -// and a boolean to check if the value has been set. -func (o *WorkspaceInfo) GetProjectsOk() ([]ProjectInfo, bool) { - if o == nil { - return nil, false - } - return o.Projects, true -} - -// SetProjects sets field value -func (o *WorkspaceInfo) SetProjects(v []ProjectInfo) { - o.Projects = v -} - -// GetProviderMetadata returns the ProviderMetadata field value if set, zero value otherwise. -func (o *WorkspaceInfo) GetProviderMetadata() string { - if o == nil || IsNil(o.ProviderMetadata) { - var ret string - return ret - } - return *o.ProviderMetadata -} - -// GetProviderMetadataOk returns a tuple with the ProviderMetadata field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *WorkspaceInfo) GetProviderMetadataOk() (*string, bool) { - if o == nil || IsNil(o.ProviderMetadata) { - return nil, false - } - return o.ProviderMetadata, true -} - -// HasProviderMetadata returns a boolean if a field has been set. -func (o *WorkspaceInfo) HasProviderMetadata() bool { - if o != nil && !IsNil(o.ProviderMetadata) { - return true - } - - return false -} - -// SetProviderMetadata gets a reference to the given string and assigns it to the ProviderMetadata field. -func (o *WorkspaceInfo) SetProviderMetadata(v string) { - o.ProviderMetadata = &v -} - -func (o WorkspaceInfo) MarshalJSON() ([]byte, error) { - toSerialize, err := o.ToMap() - if err != nil { - return []byte{}, err - } - return json.Marshal(toSerialize) -} - -func (o WorkspaceInfo) ToMap() (map[string]interface{}, error) { - toSerialize := map[string]interface{}{} - toSerialize["name"] = o.Name - toSerialize["projects"] = o.Projects - if !IsNil(o.ProviderMetadata) { - toSerialize["providerMetadata"] = o.ProviderMetadata - } - return toSerialize, nil -} - -func (o *WorkspaceInfo) UnmarshalJSON(data []byte) (err error) { - // This validates that all required properties are included in the JSON object - // by unmarshalling the object into a generic map with string keys and checking - // that every required field exists as a key in the generic map. - requiredProperties := []string{ - "name", - "projects", - } - - allProperties := make(map[string]interface{}) - - err = json.Unmarshal(data, &allProperties) - - if err != nil { - return err - } - - for _, requiredProperty := range requiredProperties { - if _, exists := allProperties[requiredProperty]; !exists { - return fmt.Errorf("no value given for required property %v", requiredProperty) - } - } - - varWorkspaceInfo := _WorkspaceInfo{} - - decoder := json.NewDecoder(bytes.NewReader(data)) - decoder.DisallowUnknownFields() - err = decoder.Decode(&varWorkspaceInfo) - - if err != nil { - return err - } - - *o = WorkspaceInfo(varWorkspaceInfo) - - return err -} - -type NullableWorkspaceInfo struct { - value *WorkspaceInfo - isSet bool -} - -func (v NullableWorkspaceInfo) Get() *WorkspaceInfo { - return v.value -} - -func (v *NullableWorkspaceInfo) Set(val *WorkspaceInfo) { - v.value = val - v.isSet = true -} - -func (v NullableWorkspaceInfo) IsSet() bool { - return v.isSet -} - -func (v *NullableWorkspaceInfo) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableWorkspaceInfo(val *WorkspaceInfo) *NullableWorkspaceInfo { - return &NullableWorkspaceInfo{value: val, isSet: true} -} - -func (v NullableWorkspaceInfo) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableWorkspaceInfo) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} diff --git a/pkg/apiclient/model_project_state.go b/pkg/apiclient/model_workspace_metadata.go similarity index 53% rename from pkg/apiclient/model_project_state.go rename to pkg/apiclient/model_workspace_metadata.go index ce3831a395..de83af8623 100644 --- a/pkg/apiclient/model_project_state.go +++ b/pkg/apiclient/model_workspace_metadata.go @@ -16,39 +16,41 @@ import ( "fmt" ) -// checks if the ProjectState type satisfies the MappedNullable interface at compile time -var _ MappedNullable = &ProjectState{} +// checks if the WorkspaceMetadata type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &WorkspaceMetadata{} -// ProjectState struct for ProjectState -type ProjectState struct { - GitStatus *GitStatus `json:"gitStatus,omitempty"` - UpdatedAt string `json:"updatedAt"` - Uptime int32 `json:"uptime"` +// WorkspaceMetadata struct for WorkspaceMetadata +type WorkspaceMetadata struct { + GitStatus *GitStatus `json:"gitStatus,omitempty"` + UpdatedAt string `json:"updatedAt"` + Uptime int32 `json:"uptime"` + WorkspaceId string `json:"workspaceId"` } -type _ProjectState ProjectState +type _WorkspaceMetadata WorkspaceMetadata -// NewProjectState instantiates a new ProjectState object +// NewWorkspaceMetadata instantiates a new WorkspaceMetadata object // This constructor will assign default values to properties that have it defined, // and makes sure properties required by API are set, but the set of arguments // will change when the set of required properties is changed -func NewProjectState(updatedAt string, uptime int32) *ProjectState { - this := ProjectState{} +func NewWorkspaceMetadata(updatedAt string, uptime int32, workspaceId string) *WorkspaceMetadata { + this := WorkspaceMetadata{} this.UpdatedAt = updatedAt this.Uptime = uptime + this.WorkspaceId = workspaceId return &this } -// NewProjectStateWithDefaults instantiates a new ProjectState object +// NewWorkspaceMetadataWithDefaults instantiates a new WorkspaceMetadata object // This constructor will only assign default values to properties that have it defined, // but it doesn't guarantee that properties required by API are set -func NewProjectStateWithDefaults() *ProjectState { - this := ProjectState{} +func NewWorkspaceMetadataWithDefaults() *WorkspaceMetadata { + this := WorkspaceMetadata{} return &this } // GetGitStatus returns the GitStatus field value if set, zero value otherwise. -func (o *ProjectState) GetGitStatus() GitStatus { +func (o *WorkspaceMetadata) GetGitStatus() GitStatus { if o == nil || IsNil(o.GitStatus) { var ret GitStatus return ret @@ -58,7 +60,7 @@ func (o *ProjectState) GetGitStatus() GitStatus { // GetGitStatusOk returns a tuple with the GitStatus field value if set, nil otherwise // and a boolean to check if the value has been set. -func (o *ProjectState) GetGitStatusOk() (*GitStatus, bool) { +func (o *WorkspaceMetadata) GetGitStatusOk() (*GitStatus, bool) { if o == nil || IsNil(o.GitStatus) { return nil, false } @@ -66,7 +68,7 @@ func (o *ProjectState) GetGitStatusOk() (*GitStatus, bool) { } // HasGitStatus returns a boolean if a field has been set. -func (o *ProjectState) HasGitStatus() bool { +func (o *WorkspaceMetadata) HasGitStatus() bool { if o != nil && !IsNil(o.GitStatus) { return true } @@ -75,12 +77,12 @@ func (o *ProjectState) HasGitStatus() bool { } // SetGitStatus gets a reference to the given GitStatus and assigns it to the GitStatus field. -func (o *ProjectState) SetGitStatus(v GitStatus) { +func (o *WorkspaceMetadata) SetGitStatus(v GitStatus) { o.GitStatus = &v } // GetUpdatedAt returns the UpdatedAt field value -func (o *ProjectState) GetUpdatedAt() string { +func (o *WorkspaceMetadata) GetUpdatedAt() string { if o == nil { var ret string return ret @@ -91,7 +93,7 @@ func (o *ProjectState) GetUpdatedAt() string { // GetUpdatedAtOk returns a tuple with the UpdatedAt field value // and a boolean to check if the value has been set. -func (o *ProjectState) GetUpdatedAtOk() (*string, bool) { +func (o *WorkspaceMetadata) GetUpdatedAtOk() (*string, bool) { if o == nil { return nil, false } @@ -99,12 +101,12 @@ func (o *ProjectState) GetUpdatedAtOk() (*string, bool) { } // SetUpdatedAt sets field value -func (o *ProjectState) SetUpdatedAt(v string) { +func (o *WorkspaceMetadata) SetUpdatedAt(v string) { o.UpdatedAt = v } // GetUptime returns the Uptime field value -func (o *ProjectState) GetUptime() int32 { +func (o *WorkspaceMetadata) GetUptime() int32 { if o == nil { var ret int32 return ret @@ -115,7 +117,7 @@ func (o *ProjectState) GetUptime() int32 { // GetUptimeOk returns a tuple with the Uptime field value // and a boolean to check if the value has been set. -func (o *ProjectState) GetUptimeOk() (*int32, bool) { +func (o *WorkspaceMetadata) GetUptimeOk() (*int32, bool) { if o == nil { return nil, false } @@ -123,11 +125,35 @@ func (o *ProjectState) GetUptimeOk() (*int32, bool) { } // SetUptime sets field value -func (o *ProjectState) SetUptime(v int32) { +func (o *WorkspaceMetadata) SetUptime(v int32) { o.Uptime = v } -func (o ProjectState) MarshalJSON() ([]byte, error) { +// GetWorkspaceId returns the WorkspaceId field value +func (o *WorkspaceMetadata) GetWorkspaceId() string { + if o == nil { + var ret string + return ret + } + + return o.WorkspaceId +} + +// GetWorkspaceIdOk returns a tuple with the WorkspaceId field value +// and a boolean to check if the value has been set. +func (o *WorkspaceMetadata) GetWorkspaceIdOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.WorkspaceId, true +} + +// SetWorkspaceId sets field value +func (o *WorkspaceMetadata) SetWorkspaceId(v string) { + o.WorkspaceId = v +} + +func (o WorkspaceMetadata) MarshalJSON() ([]byte, error) { toSerialize, err := o.ToMap() if err != nil { return []byte{}, err @@ -135,23 +161,25 @@ func (o ProjectState) MarshalJSON() ([]byte, error) { return json.Marshal(toSerialize) } -func (o ProjectState) ToMap() (map[string]interface{}, error) { +func (o WorkspaceMetadata) ToMap() (map[string]interface{}, error) { toSerialize := map[string]interface{}{} if !IsNil(o.GitStatus) { toSerialize["gitStatus"] = o.GitStatus } toSerialize["updatedAt"] = o.UpdatedAt toSerialize["uptime"] = o.Uptime + toSerialize["workspaceId"] = o.WorkspaceId return toSerialize, nil } -func (o *ProjectState) UnmarshalJSON(data []byte) (err error) { +func (o *WorkspaceMetadata) UnmarshalJSON(data []byte) (err error) { // This validates that all required properties are included in the JSON object // by unmarshalling the object into a generic map with string keys and checking // that every required field exists as a key in the generic map. requiredProperties := []string{ "updatedAt", "uptime", + "workspaceId", } allProperties := make(map[string]interface{}) @@ -168,53 +196,53 @@ func (o *ProjectState) UnmarshalJSON(data []byte) (err error) { } } - varProjectState := _ProjectState{} + varWorkspaceMetadata := _WorkspaceMetadata{} decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() - err = decoder.Decode(&varProjectState) + err = decoder.Decode(&varWorkspaceMetadata) if err != nil { return err } - *o = ProjectState(varProjectState) + *o = WorkspaceMetadata(varWorkspaceMetadata) return err } -type NullableProjectState struct { - value *ProjectState +type NullableWorkspaceMetadata struct { + value *WorkspaceMetadata isSet bool } -func (v NullableProjectState) Get() *ProjectState { +func (v NullableWorkspaceMetadata) Get() *WorkspaceMetadata { return v.value } -func (v *NullableProjectState) Set(val *ProjectState) { +func (v *NullableWorkspaceMetadata) Set(val *WorkspaceMetadata) { v.value = val v.isSet = true } -func (v NullableProjectState) IsSet() bool { +func (v NullableWorkspaceMetadata) IsSet() bool { return v.isSet } -func (v *NullableProjectState) Unset() { +func (v *NullableWorkspaceMetadata) Unset() { v.value = nil v.isSet = false } -func NewNullableProjectState(val *ProjectState) *NullableProjectState { - return &NullableProjectState{value: val, isSet: true} +func NewNullableWorkspaceMetadata(val *WorkspaceMetadata) *NullableWorkspaceMetadata { + return &NullableWorkspaceMetadata{value: val, isSet: true} } -func (v NullableProjectState) MarshalJSON() ([]byte, error) { +func (v NullableWorkspaceMetadata) MarshalJSON() ([]byte, error) { return json.Marshal(v.value) } -func (v *NullableProjectState) UnmarshalJSON(src []byte) error { +func (v *NullableWorkspaceMetadata) UnmarshalJSON(src []byte) error { v.isSet = true return json.Unmarshal(src, &v.value) } diff --git a/pkg/apiclient/model_project_config.go b/pkg/apiclient/model_workspace_template.go similarity index 64% rename from pkg/apiclient/model_project_config.go rename to pkg/apiclient/model_workspace_template.go index 2e5b034213..634d8a21cf 100644 --- a/pkg/apiclient/model_project_config.go +++ b/pkg/apiclient/model_workspace_template.go @@ -16,49 +16,51 @@ import ( "fmt" ) -// checks if the ProjectConfig type satisfies the MappedNullable interface at compile time -var _ MappedNullable = &ProjectConfig{} +// checks if the WorkspaceTemplate type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &WorkspaceTemplate{} -// ProjectConfig struct for ProjectConfig -type ProjectConfig struct { +// WorkspaceTemplate struct for WorkspaceTemplate +type WorkspaceTemplate struct { BuildConfig *BuildConfig `json:"buildConfig,omitempty"` Default bool `json:"default"` EnvVars map[string]string `json:"envVars"` GitProviderConfigId *string `json:"gitProviderConfigId,omitempty"` Image string `json:"image"` + Labels map[string]string `json:"labels"` Name string `json:"name"` Prebuilds []PrebuildConfig `json:"prebuilds,omitempty"` RepositoryUrl string `json:"repositoryUrl"` User string `json:"user"` } -type _ProjectConfig ProjectConfig +type _WorkspaceTemplate WorkspaceTemplate -// NewProjectConfig instantiates a new ProjectConfig object +// NewWorkspaceTemplate instantiates a new WorkspaceTemplate object // This constructor will assign default values to properties that have it defined, // and makes sure properties required by API are set, but the set of arguments // will change when the set of required properties is changed -func NewProjectConfig(default_ bool, envVars map[string]string, image string, name string, repositoryUrl string, user string) *ProjectConfig { - this := ProjectConfig{} +func NewWorkspaceTemplate(default_ bool, envVars map[string]string, image string, labels map[string]string, name string, repositoryUrl string, user string) *WorkspaceTemplate { + this := WorkspaceTemplate{} this.Default = default_ this.EnvVars = envVars this.Image = image + this.Labels = labels this.Name = name this.RepositoryUrl = repositoryUrl this.User = user return &this } -// NewProjectConfigWithDefaults instantiates a new ProjectConfig object +// NewWorkspaceTemplateWithDefaults instantiates a new WorkspaceTemplate object // This constructor will only assign default values to properties that have it defined, // but it doesn't guarantee that properties required by API are set -func NewProjectConfigWithDefaults() *ProjectConfig { - this := ProjectConfig{} +func NewWorkspaceTemplateWithDefaults() *WorkspaceTemplate { + this := WorkspaceTemplate{} return &this } // GetBuildConfig returns the BuildConfig field value if set, zero value otherwise. -func (o *ProjectConfig) GetBuildConfig() BuildConfig { +func (o *WorkspaceTemplate) GetBuildConfig() BuildConfig { if o == nil || IsNil(o.BuildConfig) { var ret BuildConfig return ret @@ -68,7 +70,7 @@ func (o *ProjectConfig) GetBuildConfig() BuildConfig { // GetBuildConfigOk returns a tuple with the BuildConfig field value if set, nil otherwise // and a boolean to check if the value has been set. -func (o *ProjectConfig) GetBuildConfigOk() (*BuildConfig, bool) { +func (o *WorkspaceTemplate) GetBuildConfigOk() (*BuildConfig, bool) { if o == nil || IsNil(o.BuildConfig) { return nil, false } @@ -76,7 +78,7 @@ func (o *ProjectConfig) GetBuildConfigOk() (*BuildConfig, bool) { } // HasBuildConfig returns a boolean if a field has been set. -func (o *ProjectConfig) HasBuildConfig() bool { +func (o *WorkspaceTemplate) HasBuildConfig() bool { if o != nil && !IsNil(o.BuildConfig) { return true } @@ -85,12 +87,12 @@ func (o *ProjectConfig) HasBuildConfig() bool { } // SetBuildConfig gets a reference to the given BuildConfig and assigns it to the BuildConfig field. -func (o *ProjectConfig) SetBuildConfig(v BuildConfig) { +func (o *WorkspaceTemplate) SetBuildConfig(v BuildConfig) { o.BuildConfig = &v } // GetDefault returns the Default field value -func (o *ProjectConfig) GetDefault() bool { +func (o *WorkspaceTemplate) GetDefault() bool { if o == nil { var ret bool return ret @@ -101,7 +103,7 @@ func (o *ProjectConfig) GetDefault() bool { // GetDefaultOk returns a tuple with the Default field value // and a boolean to check if the value has been set. -func (o *ProjectConfig) GetDefaultOk() (*bool, bool) { +func (o *WorkspaceTemplate) GetDefaultOk() (*bool, bool) { if o == nil { return nil, false } @@ -109,12 +111,12 @@ func (o *ProjectConfig) GetDefaultOk() (*bool, bool) { } // SetDefault sets field value -func (o *ProjectConfig) SetDefault(v bool) { +func (o *WorkspaceTemplate) SetDefault(v bool) { o.Default = v } // GetEnvVars returns the EnvVars field value -func (o *ProjectConfig) GetEnvVars() map[string]string { +func (o *WorkspaceTemplate) GetEnvVars() map[string]string { if o == nil { var ret map[string]string return ret @@ -125,7 +127,7 @@ func (o *ProjectConfig) GetEnvVars() map[string]string { // GetEnvVarsOk returns a tuple with the EnvVars field value // and a boolean to check if the value has been set. -func (o *ProjectConfig) GetEnvVarsOk() (*map[string]string, bool) { +func (o *WorkspaceTemplate) GetEnvVarsOk() (*map[string]string, bool) { if o == nil { return nil, false } @@ -133,12 +135,12 @@ func (o *ProjectConfig) GetEnvVarsOk() (*map[string]string, bool) { } // SetEnvVars sets field value -func (o *ProjectConfig) SetEnvVars(v map[string]string) { +func (o *WorkspaceTemplate) SetEnvVars(v map[string]string) { o.EnvVars = v } // GetGitProviderConfigId returns the GitProviderConfigId field value if set, zero value otherwise. -func (o *ProjectConfig) GetGitProviderConfigId() string { +func (o *WorkspaceTemplate) GetGitProviderConfigId() string { if o == nil || IsNil(o.GitProviderConfigId) { var ret string return ret @@ -148,7 +150,7 @@ func (o *ProjectConfig) GetGitProviderConfigId() string { // GetGitProviderConfigIdOk returns a tuple with the GitProviderConfigId field value if set, nil otherwise // and a boolean to check if the value has been set. -func (o *ProjectConfig) GetGitProviderConfigIdOk() (*string, bool) { +func (o *WorkspaceTemplate) GetGitProviderConfigIdOk() (*string, bool) { if o == nil || IsNil(o.GitProviderConfigId) { return nil, false } @@ -156,7 +158,7 @@ func (o *ProjectConfig) GetGitProviderConfigIdOk() (*string, bool) { } // HasGitProviderConfigId returns a boolean if a field has been set. -func (o *ProjectConfig) HasGitProviderConfigId() bool { +func (o *WorkspaceTemplate) HasGitProviderConfigId() bool { if o != nil && !IsNil(o.GitProviderConfigId) { return true } @@ -165,12 +167,12 @@ func (o *ProjectConfig) HasGitProviderConfigId() bool { } // SetGitProviderConfigId gets a reference to the given string and assigns it to the GitProviderConfigId field. -func (o *ProjectConfig) SetGitProviderConfigId(v string) { +func (o *WorkspaceTemplate) SetGitProviderConfigId(v string) { o.GitProviderConfigId = &v } // GetImage returns the Image field value -func (o *ProjectConfig) GetImage() string { +func (o *WorkspaceTemplate) GetImage() string { if o == nil { var ret string return ret @@ -181,7 +183,7 @@ func (o *ProjectConfig) GetImage() string { // GetImageOk returns a tuple with the Image field value // and a boolean to check if the value has been set. -func (o *ProjectConfig) GetImageOk() (*string, bool) { +func (o *WorkspaceTemplate) GetImageOk() (*string, bool) { if o == nil { return nil, false } @@ -189,12 +191,36 @@ func (o *ProjectConfig) GetImageOk() (*string, bool) { } // SetImage sets field value -func (o *ProjectConfig) SetImage(v string) { +func (o *WorkspaceTemplate) SetImage(v string) { o.Image = v } +// GetLabels returns the Labels field value +func (o *WorkspaceTemplate) GetLabels() map[string]string { + if o == nil { + var ret map[string]string + return ret + } + + return o.Labels +} + +// GetLabelsOk returns a tuple with the Labels field value +// and a boolean to check if the value has been set. +func (o *WorkspaceTemplate) GetLabelsOk() (*map[string]string, bool) { + if o == nil { + return nil, false + } + return &o.Labels, true +} + +// SetLabels sets field value +func (o *WorkspaceTemplate) SetLabels(v map[string]string) { + o.Labels = v +} + // GetName returns the Name field value -func (o *ProjectConfig) GetName() string { +func (o *WorkspaceTemplate) GetName() string { if o == nil { var ret string return ret @@ -205,7 +231,7 @@ func (o *ProjectConfig) GetName() string { // GetNameOk returns a tuple with the Name field value // and a boolean to check if the value has been set. -func (o *ProjectConfig) GetNameOk() (*string, bool) { +func (o *WorkspaceTemplate) GetNameOk() (*string, bool) { if o == nil { return nil, false } @@ -213,12 +239,12 @@ func (o *ProjectConfig) GetNameOk() (*string, bool) { } // SetName sets field value -func (o *ProjectConfig) SetName(v string) { +func (o *WorkspaceTemplate) SetName(v string) { o.Name = v } // GetPrebuilds returns the Prebuilds field value if set, zero value otherwise. -func (o *ProjectConfig) GetPrebuilds() []PrebuildConfig { +func (o *WorkspaceTemplate) GetPrebuilds() []PrebuildConfig { if o == nil || IsNil(o.Prebuilds) { var ret []PrebuildConfig return ret @@ -228,7 +254,7 @@ func (o *ProjectConfig) GetPrebuilds() []PrebuildConfig { // GetPrebuildsOk returns a tuple with the Prebuilds field value if set, nil otherwise // and a boolean to check if the value has been set. -func (o *ProjectConfig) GetPrebuildsOk() ([]PrebuildConfig, bool) { +func (o *WorkspaceTemplate) GetPrebuildsOk() ([]PrebuildConfig, bool) { if o == nil || IsNil(o.Prebuilds) { return nil, false } @@ -236,7 +262,7 @@ func (o *ProjectConfig) GetPrebuildsOk() ([]PrebuildConfig, bool) { } // HasPrebuilds returns a boolean if a field has been set. -func (o *ProjectConfig) HasPrebuilds() bool { +func (o *WorkspaceTemplate) HasPrebuilds() bool { if o != nil && !IsNil(o.Prebuilds) { return true } @@ -245,12 +271,12 @@ func (o *ProjectConfig) HasPrebuilds() bool { } // SetPrebuilds gets a reference to the given []PrebuildConfig and assigns it to the Prebuilds field. -func (o *ProjectConfig) SetPrebuilds(v []PrebuildConfig) { +func (o *WorkspaceTemplate) SetPrebuilds(v []PrebuildConfig) { o.Prebuilds = v } // GetRepositoryUrl returns the RepositoryUrl field value -func (o *ProjectConfig) GetRepositoryUrl() string { +func (o *WorkspaceTemplate) GetRepositoryUrl() string { if o == nil { var ret string return ret @@ -261,7 +287,7 @@ func (o *ProjectConfig) GetRepositoryUrl() string { // GetRepositoryUrlOk returns a tuple with the RepositoryUrl field value // and a boolean to check if the value has been set. -func (o *ProjectConfig) GetRepositoryUrlOk() (*string, bool) { +func (o *WorkspaceTemplate) GetRepositoryUrlOk() (*string, bool) { if o == nil { return nil, false } @@ -269,12 +295,12 @@ func (o *ProjectConfig) GetRepositoryUrlOk() (*string, bool) { } // SetRepositoryUrl sets field value -func (o *ProjectConfig) SetRepositoryUrl(v string) { +func (o *WorkspaceTemplate) SetRepositoryUrl(v string) { o.RepositoryUrl = v } // GetUser returns the User field value -func (o *ProjectConfig) GetUser() string { +func (o *WorkspaceTemplate) GetUser() string { if o == nil { var ret string return ret @@ -285,7 +311,7 @@ func (o *ProjectConfig) GetUser() string { // GetUserOk returns a tuple with the User field value // and a boolean to check if the value has been set. -func (o *ProjectConfig) GetUserOk() (*string, bool) { +func (o *WorkspaceTemplate) GetUserOk() (*string, bool) { if o == nil { return nil, false } @@ -293,11 +319,11 @@ func (o *ProjectConfig) GetUserOk() (*string, bool) { } // SetUser sets field value -func (o *ProjectConfig) SetUser(v string) { +func (o *WorkspaceTemplate) SetUser(v string) { o.User = v } -func (o ProjectConfig) MarshalJSON() ([]byte, error) { +func (o WorkspaceTemplate) MarshalJSON() ([]byte, error) { toSerialize, err := o.ToMap() if err != nil { return []byte{}, err @@ -305,7 +331,7 @@ func (o ProjectConfig) MarshalJSON() ([]byte, error) { return json.Marshal(toSerialize) } -func (o ProjectConfig) ToMap() (map[string]interface{}, error) { +func (o WorkspaceTemplate) ToMap() (map[string]interface{}, error) { toSerialize := map[string]interface{}{} if !IsNil(o.BuildConfig) { toSerialize["buildConfig"] = o.BuildConfig @@ -316,6 +342,7 @@ func (o ProjectConfig) ToMap() (map[string]interface{}, error) { toSerialize["gitProviderConfigId"] = o.GitProviderConfigId } toSerialize["image"] = o.Image + toSerialize["labels"] = o.Labels toSerialize["name"] = o.Name if !IsNil(o.Prebuilds) { toSerialize["prebuilds"] = o.Prebuilds @@ -325,7 +352,7 @@ func (o ProjectConfig) ToMap() (map[string]interface{}, error) { return toSerialize, nil } -func (o *ProjectConfig) UnmarshalJSON(data []byte) (err error) { +func (o *WorkspaceTemplate) UnmarshalJSON(data []byte) (err error) { // This validates that all required properties are included in the JSON object // by unmarshalling the object into a generic map with string keys and checking // that every required field exists as a key in the generic map. @@ -333,6 +360,7 @@ func (o *ProjectConfig) UnmarshalJSON(data []byte) (err error) { "default", "envVars", "image", + "labels", "name", "repositoryUrl", "user", @@ -352,53 +380,53 @@ func (o *ProjectConfig) UnmarshalJSON(data []byte) (err error) { } } - varProjectConfig := _ProjectConfig{} + varWorkspaceTemplate := _WorkspaceTemplate{} decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() - err = decoder.Decode(&varProjectConfig) + err = decoder.Decode(&varWorkspaceTemplate) if err != nil { return err } - *o = ProjectConfig(varProjectConfig) + *o = WorkspaceTemplate(varWorkspaceTemplate) return err } -type NullableProjectConfig struct { - value *ProjectConfig +type NullableWorkspaceTemplate struct { + value *WorkspaceTemplate isSet bool } -func (v NullableProjectConfig) Get() *ProjectConfig { +func (v NullableWorkspaceTemplate) Get() *WorkspaceTemplate { return v.value } -func (v *NullableProjectConfig) Set(val *ProjectConfig) { +func (v *NullableWorkspaceTemplate) Set(val *WorkspaceTemplate) { v.value = val v.isSet = true } -func (v NullableProjectConfig) IsSet() bool { +func (v NullableWorkspaceTemplate) IsSet() bool { return v.isSet } -func (v *NullableProjectConfig) Unset() { +func (v *NullableWorkspaceTemplate) Unset() { v.value = nil v.isSet = false } -func NewNullableProjectConfig(val *ProjectConfig) *NullableProjectConfig { - return &NullableProjectConfig{value: val, isSet: true} +func NewNullableWorkspaceTemplate(val *WorkspaceTemplate) *NullableWorkspaceTemplate { + return &NullableWorkspaceTemplate{value: val, isSet: true} } -func (v NullableProjectConfig) MarshalJSON() ([]byte, error) { +func (v NullableWorkspaceTemplate) MarshalJSON() ([]byte, error) { return json.Marshal(v.value) } -func (v *NullableProjectConfig) UnmarshalJSON(src []byte) error { +func (v *NullableWorkspaceTemplate) UnmarshalJSON(src []byte) error { v.isSet = true return json.Unmarshal(src, &v.value) } diff --git a/pkg/apikey/apikey.go b/pkg/apikey/apikey.go deleted file mode 100644 index 2900bca156..0000000000 --- a/pkg/apikey/apikey.go +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package apikey - -type ApiKeyType string - -const ( - ApiKeyTypeClient ApiKeyType = "client" - ApiKeyTypeProject ApiKeyType = "project" - ApiKeyTypeWorkspace ApiKeyType = "workspace" -) - -type ApiKey struct { - KeyHash string `json:"keyHash" validate:"required"` - Type ApiKeyType `json:"type" validate:"required"` - // Project or client name - Name string `json:"name" validate:"required"` -} // @name ApiKey diff --git a/pkg/apikey/store.go b/pkg/apikey/store.go deleted file mode 100644 index be44c9dd10..0000000000 --- a/pkg/apikey/store.go +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package apikey - -import "errors" - -type Store interface { - List() ([]*ApiKey, error) - Find(key string) (*ApiKey, error) - FindByName(name string) (*ApiKey, error) - Save(apiKey *ApiKey) error - Delete(apiKey *ApiKey) error -} - -var ( - ErrApiKeyNotFound = errors.New("api key not found") -) - -func IsApiKeyNotFound(err error) bool { - return err.Error() == ErrApiKeyNotFound.Error() -} diff --git a/pkg/build/builder.go b/pkg/build/builder.go index cda12f2ce9..277d9b63a5 100644 --- a/pkg/build/builder.go +++ b/pkg/build/builder.go @@ -8,31 +8,32 @@ import ( "encoding/hex" "fmt" - "github.com/daytonaio/daytona/pkg/containerregistry" + "github.com/daytonaio/daytona/pkg/common" "github.com/daytonaio/daytona/pkg/logs" + "github.com/daytonaio/daytona/pkg/models" ) type IBuilder interface { - Build(build Build) (string, string, error) + Build(build models.Build) (string, string, error) CleanUp() error - Publish(build Build) error - GetImageName(build Build) (string, error) + Publish(build models.Build) error + GetImageName(build models.Build) (string, error) } type Builder struct { id string - projectDir string + workspaceDir string image string - containerRegistry *containerregistry.ContainerRegistry - buildImageContainerRegistry *containerregistry.ContainerRegistry - buildStore Store - buildImageNamespace string - loggerFactory logs.LoggerFactory - defaultProjectImage string - defaultProjectUser string + containerRegistries common.ContainerRegistries + buildImageContainerRegistry *models.ContainerRegistry + + buildImageNamespace string + loggerFactory logs.ILoggerFactory + defaultWorkspaceImage string + defaultWorkspaceUser string } -func (b *Builder) GetImageName(build Build) (string, error) { +func (b *Builder) GetImageName(build models.Build) (string, error) { hash, err := build.GetBuildHash() if err != nil { return "", err @@ -44,7 +45,7 @@ func (b *Builder) GetImageName(build Build) (string, error) { name := hex.EncodeToString(nameBytes[:])[:16] namespace := b.buildImageNamespace - imageName := fmt.Sprintf("%s%s/p-%s:%s", b.buildImageContainerRegistry.Server, namespace, name, tag) + imageName := fmt.Sprintf("%s%s/w-%s:%s", b.buildImageContainerRegistry.Server, namespace, name, tag) return imageName, nil } diff --git a/pkg/build/builder_test.go b/pkg/build/builder_test.go deleted file mode 100644 index 8ca66b4d07..0000000000 --- a/pkg/build/builder_test.go +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package build_test - -import ( - "testing" - - t_build "github.com/daytonaio/daytona/internal/testing/build" - git_mocks "github.com/daytonaio/daytona/internal/testing/git/mocks" - builder_mocks "github.com/daytonaio/daytona/internal/testing/server/workspaces/mocks" - "github.com/daytonaio/daytona/pkg/build" - "github.com/stretchr/testify/suite" -) - -var expectedBuilds []*build.Build - -type BuilderTestSuite struct { - suite.Suite - mockGitService *git_mocks.MockGitService - mockBuildStore build.Store - builder build.IBuilder -} - -func NewBuilderTestSuite() *BuilderTestSuite { - return &BuilderTestSuite{} -} - -func (s *BuilderTestSuite) SetupTest() { - s.mockBuildStore = t_build.NewInMemoryBuildStore() - s.mockGitService = git_mocks.NewMockGitService() - factory := build.NewBuilderFactory(build.BuilderFactoryConfig{ - BuildStore: s.mockBuildStore, - }) - s.builder, _ = factory.Create(*builder_mocks.MockBuild, "") - err := s.mockBuildStore.Save(builder_mocks.MockBuild) - if err != nil { - panic(err) - } -} - -func TestBuilder(t *testing.T) { - suite.Run(t, NewBuilderTestSuite()) -} - -func (s *BuilderTestSuite) TestSaveBuild() { - expectedBuilds = append(expectedBuilds, builder_mocks.MockBuild) - - require := s.Require() - - err := s.mockBuildStore.Save(builder_mocks.MockBuild) - require.NoError(err) - - savedBuilds, err := s.mockBuildStore.List(nil) - require.NoError(err) - require.ElementsMatch(expectedBuilds, savedBuilds) -} diff --git a/pkg/build/detect/detect.go b/pkg/build/detect/detect.go index 81e47ade94..6bbbd431e9 100644 --- a/pkg/build/detect/detect.go +++ b/pkg/build/detect/detect.go @@ -8,8 +8,8 @@ import ( "path" "path/filepath" + "github.com/daytonaio/daytona/pkg/models" "github.com/daytonaio/daytona/pkg/ssh" - "github.com/daytonaio/daytona/pkg/workspace/project/buildconfig" ) type BuilderType string @@ -19,7 +19,7 @@ var ( BuilderTypeImage BuilderType = "image" ) -func DetectProjectBuilderType(buildConfig *buildconfig.BuildConfig, projectDir string, sshClient *ssh.Client) (BuilderType, error) { +func DetectWorkspaceBuilderType(buildConfig *models.BuildConfig, workspaceDir string, sshClient *ssh.Client) (BuilderType, error) { if buildConfig == nil { return BuilderTypeImage, nil } @@ -29,21 +29,21 @@ func DetectProjectBuilderType(buildConfig *buildconfig.BuildConfig, projectDir s } if sshClient != nil { - if _, err := sshClient.ReadFile(path.Join(projectDir, ".devcontainer/devcontainer.json")); err == nil { - buildConfig.Devcontainer = &buildconfig.DevcontainerConfig{ + if _, err := sshClient.ReadFile(path.Join(workspaceDir, ".devcontainer/devcontainer.json")); err == nil { + buildConfig.Devcontainer = &models.DevcontainerConfig{ FilePath: ".devcontainer/devcontainer.json", } return BuilderTypeDevcontainer, nil } - if _, err := sshClient.ReadFile(path.Join(projectDir, ".devcontainer.json")); err == nil { - buildConfig.Devcontainer = &buildconfig.DevcontainerConfig{ + if _, err := sshClient.ReadFile(path.Join(workspaceDir, ".devcontainer.json")); err == nil { + buildConfig.Devcontainer = &models.DevcontainerConfig{ FilePath: ".devcontainer.json", } return BuilderTypeDevcontainer, nil } } else { - if devcontainerFilePath, pathError := findDevcontainerConfigFilePath(projectDir); pathError == nil { - buildConfig.Devcontainer = &buildconfig.DevcontainerConfig{ + if devcontainerFilePath, pathError := findDevcontainerConfigFilePath(workspaceDir); pathError == nil { + buildConfig.Devcontainer = &models.DevcontainerConfig{ FilePath: devcontainerFilePath, } @@ -54,12 +54,12 @@ func DetectProjectBuilderType(buildConfig *buildconfig.BuildConfig, projectDir s return BuilderTypeImage, nil } -func findDevcontainerConfigFilePath(projectDir string) (string, error) { +func findDevcontainerConfigFilePath(workspaceDir string) (string, error) { devcontainerPath := ".devcontainer/devcontainer.json" - isDevcontainer, err := fileExists(filepath.Join(projectDir, devcontainerPath)) + isDevcontainer, err := fileExists(filepath.Join(workspaceDir, devcontainerPath)) if !isDevcontainer || err != nil { devcontainerPath = ".devcontainer.json" - isDevcontainer, err = fileExists(filepath.Join(projectDir, devcontainerPath)) + isDevcontainer, err = fileExists(filepath.Join(workspaceDir, devcontainerPath)) if err != nil { return devcontainerPath, nil } diff --git a/pkg/build/devcontainer.go b/pkg/build/devcontainer.go index 922545abf3..374e298c7e 100644 --- a/pkg/build/devcontainer.go +++ b/pkg/build/devcontainer.go @@ -11,6 +11,7 @@ import ( "github.com/daytonaio/daytona/pkg/build/detect" "github.com/daytonaio/daytona/pkg/docker" "github.com/daytonaio/daytona/pkg/logs" + "github.com/daytonaio/daytona/pkg/models" "github.com/docker/docker/api/types/container" "github.com/docker/docker/client" ) @@ -27,8 +28,8 @@ type DevcontainerBuilder struct { builderDockerPort uint16 } -func (b *DevcontainerBuilder) Build(build Build) (string, string, error) { - builderType, err := detect.DetectProjectBuilderType(build.BuildConfig, b.projectDir, nil) +func (b *DevcontainerBuilder) Build(build models.Build) (string, string, error) { + builderType, err := detect.DetectWorkspaceBuilderType(build.BuildConfig, b.workspaceDir, nil) if err != nil { return "", "", err } @@ -41,11 +42,14 @@ func (b *DevcontainerBuilder) Build(build Build) (string, string, error) { } func (b *DevcontainerBuilder) CleanUp() error { - return os.RemoveAll(b.projectDir) + return os.RemoveAll(b.workspaceDir) } -func (b *DevcontainerBuilder) Publish(build Build) error { - buildLogger := b.loggerFactory.CreateBuildLogger(build.Id, logs.LogSourceBuilder) +func (b *DevcontainerBuilder) Publish(build models.Build) error { + buildLogger, err := b.loggerFactory.CreateLogger(build.Id, build.Id, logs.LogSourceBuilder) + if err != nil { + return err + } defer buildLogger.Close() cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) @@ -64,54 +68,57 @@ func (b *DevcontainerBuilder) Publish(build Build) error { return dockerClient.PushImage(*build.Image, b.buildImageContainerRegistry, buildLogger) } -func (b *DevcontainerBuilder) buildDevcontainer(build Build) (string, string, error) { - buildLogger := b.loggerFactory.CreateBuildLogger(build.Id, logs.LogSourceBuilder) +func (b *DevcontainerBuilder) buildDevcontainer(build models.Build) (string, string, error) { + buildLogger, err := b.loggerFactory.CreateLogger(build.Id, build.Id, logs.LogSourceBuilder) + if err != nil { + return b.defaultWorkspaceImage, b.defaultWorkspaceUser, err + } defer buildLogger.Close() cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) if err != nil { - return b.defaultProjectImage, b.defaultProjectUser, err + return b.defaultWorkspaceImage, b.defaultWorkspaceUser, err } dockerClient := docker.NewDockerClient(docker.DockerClientConfig{ ApiClient: cli, }) - err = dockerClient.PullImage(b.image, b.containerRegistry, buildLogger) + cr := b.containerRegistries.FindContainerRegistryByImageName(b.image) + err = dockerClient.PullImage(b.image, cr, buildLogger) if err != nil { - return b.defaultProjectImage, b.defaultProjectUser, err + return b.defaultWorkspaceImage, b.defaultWorkspaceUser, err } containerId, remoteUser, err := dockerClient.CreateFromDevcontainer(docker.CreateDevcontainerOptions{ - BuildConfig: build.BuildConfig, - ProjectName: build.Id, - ContainerRegistry: b.buildImageContainerRegistry, - BuilderImage: b.image, - BuilderContainerRegistry: b.containerRegistry, - Prebuild: true, + BuildConfig: build.BuildConfig, + WorkspaceFolderName: build.Id, + ContainerRegistries: b.containerRegistries, + BuilderImage: b.image, + Prebuild: true, IdLabels: map[string]string{ "daytona.build.id": build.Id, }, - ProjectDir: b.projectDir, - LogWriter: buildLogger, - EnvVars: build.EnvVars, + WorkspaceDir: b.workspaceDir, + LogWriter: buildLogger, + EnvVars: build.EnvVars, }) if err != nil { - return b.defaultProjectImage, b.defaultProjectUser, err + return b.defaultWorkspaceImage, b.defaultWorkspaceUser, err } defer dockerClient.RemoveContainer(containerId) // nolint: errcheck imageName, err := b.GetImageName(build) if err != nil { - return b.defaultProjectImage, b.defaultProjectUser, err + return b.defaultWorkspaceImage, b.defaultWorkspaceUser, err } _, err = cli.ContainerCommit(context.Background(), containerId, container.CommitOptions{ Reference: imageName, }) if err != nil { - return b.defaultProjectImage, b.defaultProjectUser, err + return b.defaultWorkspaceImage, b.defaultWorkspaceUser, err } return imageName, string(remoteUser), err diff --git a/pkg/build/factory.go b/pkg/build/factory.go index 04b3830696..4eceab7108 100644 --- a/pkg/build/factory.go +++ b/pkg/build/factory.go @@ -4,79 +4,57 @@ package build import ( - "errors" "fmt" - "github.com/daytonaio/daytona/pkg/containerregistry" + "github.com/daytonaio/daytona/pkg/common" "github.com/daytonaio/daytona/pkg/logs" + "github.com/daytonaio/daytona/pkg/models" "github.com/daytonaio/daytona/pkg/ports" "github.com/docker/docker/pkg/stringid" ) type IBuilderFactory interface { - Create(build Build, projectDir string) (IBuilder, error) - CheckExistingBuild(build Build) (*Build, error) + Create(build models.Build, workspaceDir string) (IBuilder, error) } type BuilderFactory struct { - containerRegistry *containerregistry.ContainerRegistry - buildImageContainerRegistry *containerregistry.ContainerRegistry + containerRegistries common.ContainerRegistries + buildImageContainerRegistry *models.ContainerRegistry buildImageNamespace string - buildStore Store - loggerFactory logs.LoggerFactory + loggerFactory logs.ILoggerFactory image string - defaultProjectImage string - defaultProjectUser string + defaultWorkspaceImage string + defaultWorkspaceUser string } type BuilderFactoryConfig struct { Image string - ContainerRegistry *containerregistry.ContainerRegistry - BuildImageContainerRegistry *containerregistry.ContainerRegistry - BuildStore Store + ContainerRegistries common.ContainerRegistries + BuildImageContainerRegistry *models.ContainerRegistry BuildImageNamespace string // Namespace to be used when tagging and pushing the build image - LoggerFactory logs.LoggerFactory - DefaultProjectImage string - DefaultProjectUser string + LoggerFactory logs.ILoggerFactory + DefaultWorkspaceImage string + DefaultWorkspaceUser string } func NewBuilderFactory(config BuilderFactoryConfig) IBuilderFactory { return &BuilderFactory{ image: config.Image, - containerRegistry: config.ContainerRegistry, + containerRegistries: config.ContainerRegistries, buildImageNamespace: config.BuildImageNamespace, buildImageContainerRegistry: config.BuildImageContainerRegistry, - buildStore: config.BuildStore, loggerFactory: config.LoggerFactory, - defaultProjectImage: config.DefaultProjectImage, - defaultProjectUser: config.DefaultProjectUser, + defaultWorkspaceImage: config.DefaultWorkspaceImage, + defaultWorkspaceUser: config.DefaultWorkspaceUser, } } -func (f *BuilderFactory) Create(build Build, projectDir string) (IBuilder, error) { +func (f *BuilderFactory) Create(build models.Build, workspaceDir string) (IBuilder, error) { // TODO: Implement factory logic after adding prebuilds and other builder types - return f.newDevcontainerBuilder(projectDir) + return f.newDevcontainerBuilder(workspaceDir) } -func (f *BuilderFactory) CheckExistingBuild(b Build) (*Build, error) { - if b.Repository == nil { - return nil, errors.New("repository must be set") - } - - build, err := f.buildStore.Find(&Filter{ - Branch: &b.Repository.Branch, - RepositoryUrl: &b.Repository.Url, - BuildConfig: b.BuildConfig, - EnvVars: &b.EnvVars, - }) - if err != nil { - return nil, err - } - - return build, nil -} - -func (f *BuilderFactory) newDevcontainerBuilder(projectDir string) (*DevcontainerBuilder, error) { +func (f *BuilderFactory) newDevcontainerBuilder(workspaceDir string) (*DevcontainerBuilder, error) { builderDockerPort, err := ports.GetAvailableEphemeralPort() if err != nil { return nil, err @@ -89,15 +67,14 @@ func (f *BuilderFactory) newDevcontainerBuilder(projectDir string) (*Devcontaine return &DevcontainerBuilder{ Builder: &Builder{ id: id, - projectDir: projectDir, + workspaceDir: workspaceDir, image: f.image, - containerRegistry: f.containerRegistry, + containerRegistries: f.containerRegistries, buildImageContainerRegistry: f.buildImageContainerRegistry, buildImageNamespace: f.buildImageNamespace, - buildStore: f.buildStore, loggerFactory: f.loggerFactory, - defaultProjectImage: f.defaultProjectImage, - defaultProjectUser: f.defaultProjectUser, + defaultWorkspaceImage: f.defaultWorkspaceImage, + defaultWorkspaceUser: f.defaultWorkspaceUser, }, builderDockerPort: builderDockerPort, }, nil diff --git a/pkg/build/logs.go b/pkg/build/logs.go deleted file mode 100644 index b976e57cd5..0000000000 --- a/pkg/build/logs.go +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package build - -import ( - "path/filepath" - - "github.com/daytonaio/daytona/cmd/daytona/config" -) - -func GetBuildLogsDir() (string, error) { - configDir, err := config.GetConfigDir() - if err != nil { - return "", err - } - - return filepath.Join(configDir, "builds", "logs"), nil -} diff --git a/pkg/build/mocks/gitprovider_config_store.go b/pkg/build/mocks/gitprovider_config_store.go index 46f18054ef..173f166c62 100644 --- a/pkg/build/mocks/gitprovider_config_store.go +++ b/pkg/build/mocks/gitprovider_config_store.go @@ -4,7 +4,9 @@ package build import ( - "github.com/daytonaio/daytona/pkg/gitprovider" + "context" + + "github.com/daytonaio/daytona/pkg/models" "github.com/stretchr/testify/mock" ) @@ -12,7 +14,7 @@ type MockGitProviderConfigStore struct { mock.Mock } -func (s *MockGitProviderConfigStore) ListConfigsForUrl(url string) ([]*gitprovider.GitProviderConfig, error) { - args := s.Called(url) - return args.Get(0).([]*gitprovider.GitProviderConfig), args.Error(1) +func (s *MockGitProviderConfigStore) ListConfigsForUrl(ctx context.Context, url string) ([]*models.GitProviderConfig, error) { + args := s.Called(ctx, url) + return args.Get(0).([]*models.GitProviderConfig), args.Error(1) } diff --git a/pkg/build/runner.go b/pkg/build/runner.go deleted file mode 100644 index d73b6a6d1d..0000000000 --- a/pkg/build/runner.go +++ /dev/null @@ -1,340 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package build - -import ( - "context" - "fmt" - "path/filepath" - "sync" - - "github.com/charmbracelet/lipgloss" - "github.com/daytonaio/daytona/pkg/containerregistry" - "github.com/daytonaio/daytona/pkg/docker" - "github.com/daytonaio/daytona/pkg/git" - "github.com/daytonaio/daytona/pkg/gitprovider" - "github.com/daytonaio/daytona/pkg/logs" - "github.com/daytonaio/daytona/pkg/scheduler" - "github.com/daytonaio/daytona/pkg/telemetry" - "github.com/docker/docker/client" - "github.com/go-git/go-git/v5/plumbing/transport/http" - log "github.com/sirupsen/logrus" -) - -type BuildRunnerInstanceConfig struct { - Interval string - Scheduler scheduler.IScheduler - BuildRunnerId string - ContainerRegistry *containerregistry.ContainerRegistry - GitProviderStore GitProviderStore - BuildStore Store - BuilderFactory IBuilderFactory - LoggerFactory logs.LoggerFactory - BasePath string - TelemetryEnabled bool - TelemetryService telemetry.TelemetryService -} - -type BuildRunner struct { - Id string - scheduler scheduler.IScheduler - runInterval string - containerRegistry *containerregistry.ContainerRegistry - gitProviderStore GitProviderStore - buildStore Store - builderFactory IBuilderFactory - loggerFactory logs.LoggerFactory - basePath string - telemetryEnabled bool - telemetryService telemetry.TelemetryService -} - -type BuildProcessConfig struct { - Builder IBuilder - BuildLogger logs.Logger - Build *Build - ProjectDir string - GitService git.IGitService - Wg *sync.WaitGroup -} - -type GitProviderStore interface { - ListConfigsForUrl(url string) ([]*gitprovider.GitProviderConfig, error) -} - -func NewBuildRunner(config BuildRunnerInstanceConfig) *BuildRunner { - runner := &BuildRunner{ - Id: config.BuildRunnerId, - scheduler: config.Scheduler, - runInterval: config.Interval, - containerRegistry: config.ContainerRegistry, - gitProviderStore: config.GitProviderStore, - buildStore: config.BuildStore, - builderFactory: config.BuilderFactory, - loggerFactory: config.LoggerFactory, - basePath: config.BasePath, - telemetryEnabled: config.TelemetryEnabled, - telemetryService: config.TelemetryService, - } - - return runner -} - -func (r *BuildRunner) Start() error { - err := r.scheduler.AddFunc(r.runInterval, func() { r.RunBuilds() }) - if err != nil { - return err - } - err = r.scheduler.AddFunc(r.runInterval, func() { r.DeleteBuilds() }) - if err != nil { - return err - } - - r.scheduler.Start() - return nil -} - -func (r *BuildRunner) Stop() { - r.scheduler.Stop() -} - -func (r *BuildRunner) RunBuilds() { - builds, err := r.buildStore.List(&Filter{ - States: &[]BuildState{BuildStatePendingRun, BuildStatePublished}, - }) - if err != nil { - log.Error(err) - return - } - - var wg sync.WaitGroup - for _, b := range builds { - if b.State == BuildStatePendingRun { - wg.Add(1) - - if b.BuildConfig == nil { - return - } - - buildLogger := r.loggerFactory.CreateBuildLogger(b.Id, logs.LogSourceBuilder) - defer buildLogger.Close() - - projectDir := filepath.Join(r.basePath, b.Id, "project") - - builder, err := r.builderFactory.Create(*b, projectDir) - if err != nil { - r.handleBuildError(*b, builder, err, buildLogger) - return - } - - cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) - if err != nil { - log.Error(err) - return - } - - imageName, err := builder.GetImageName(*b) - if err != nil { - r.handleBuildError(*b, builder, err, buildLogger) - return - } - - _, _, err = cli.ImageInspectWithRaw(context.Background(), imageName) - if err == nil { - b.State = BuildStatePublished - err = r.buildStore.Save(b) - if err != nil { - r.handleBuildError(*b, builder, err, buildLogger) - return - } - return - } - - b.BuildConfig.CachedBuild = GetCachedBuild(b, builds) - - go r.RunBuildProcess(BuildProcessConfig{ - Builder: builder, - BuildLogger: buildLogger, - Build: b, - ProjectDir: projectDir, - GitService: &git.Service{ - ProjectDir: projectDir, - LogWriter: buildLogger, - }, - Wg: &wg, - }) - } - } - - wg.Wait() -} - -func (r *BuildRunner) DeleteBuilds() { - markedForDeletionBuilds, err := r.buildStore.List(&Filter{ - States: &[]BuildState{BuildStatePendingDelete, BuildStatePendingForcedDelete}, - }) - if err != nil { - log.Error(err) - return - } - - cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) - if err != nil { - log.Error(err) - return - } - - dockerClient := docker.NewDockerClient(docker.DockerClientConfig{ - ApiClient: cli, - }) - - var wg sync.WaitGroup - for _, b := range markedForDeletionBuilds { - wg.Add(1) - - go func(b *Build) { - buildLogger := r.loggerFactory.CreateBuildLogger(b.Id, logs.LogSourceBuilder) - defer buildLogger.Close() - - force := b.State == BuildStatePendingForcedDelete - - b.State = BuildStateDeleting - err = r.buildStore.Save(b) - if err != nil { - r.handleBuildError(*b, nil, err, buildLogger) - return - } - - // If the build has an image, delete it first - if b.Image != nil { - err := dockerClient.DeleteImage(*b.Image, true, nil) - if err != nil { - r.handleBuildError(*b, nil, err, buildLogger) - if !force { - return - } - } - } - - err = r.buildStore.Delete(b.Id) - if err != nil { - r.handleBuildError(*b, nil, err, buildLogger) - return - } - }(b) - } - - wg.Wait() -} - -func (r *BuildRunner) RunBuildProcess(config BuildProcessConfig) { - if config.Wg != nil { - defer config.Wg.Done() - } - - config.Build.State = BuildStateRunning - err := r.buildStore.Save(config.Build) - if err != nil { - r.handleBuildError(*config.Build, config.Builder, err, config.BuildLogger) - return - } - - gitProviders, err := r.gitProviderStore.ListConfigsForUrl(config.Build.Repository.Url) - if err != nil { - r.handleBuildError(*config.Build, config.Builder, err, config.BuildLogger) - return - } - - var auth *http.BasicAuth - if len(gitProviders) > 0 { - auth = &http.BasicAuth{} - auth.Username = gitProviders[0].Username - auth.Password = gitProviders[0].Token - } - - err = config.GitService.CloneRepository(config.Build.Repository, auth) - if err != nil { - r.handleBuildError(*config.Build, config.Builder, err, config.BuildLogger) - return - } - - image, user, err := config.Builder.Build(*config.Build) - if err != nil { - r.handleBuildError(*config.Build, config.Builder, err, config.BuildLogger) - return - } - - config.Build.Image = &image - config.Build.User = &user - config.Build.State = BuildStateSuccess - err = r.buildStore.Save(config.Build) - if err != nil { - r.handleBuildError(*config.Build, config.Builder, err, config.BuildLogger) - return - } - - err = config.Builder.Publish(*config.Build) - if err != nil { - r.handleBuildError(*config.Build, config.Builder, err, config.BuildLogger) - return - } - - config.Build.State = BuildStatePublished - err = r.buildStore.Save(config.Build) - if err != nil { - r.handleBuildError(*config.Build, config.Builder, err, config.BuildLogger) - return - } - - err = config.Builder.CleanUp() - if err != nil { - errMsg := fmt.Sprintf("Error cleaning up build: %s\n", err.Error()) - config.BuildLogger.Write([]byte(errMsg + "\n")) - } - - config.BuildLogger.Write([]byte("\n \n" + lipgloss.NewStyle().Bold(true).Render("Build completed successfully"))) - - if r.telemetryEnabled { - r.logTelemetry(context.Background(), *config.Build, err) - } -} - -func (r *BuildRunner) handleBuildError(b Build, builder IBuilder, err error, buildLogger logs.Logger) { - var errMsg string - errMsg += "################################################\n" - errMsg += fmt.Sprintf("#### BUILD FAILED FOR %s: %s\n", b.Id, err.Error()) - errMsg += "################################################\n" - - b.State = BuildStateError - err = r.buildStore.Save(&b) - if err != nil { - errMsg += fmt.Sprintf("Error saving build: %s\n", err.Error()) - } - - if builder != nil { - cleanupErr := builder.CleanUp() - if cleanupErr != nil { - errMsg += fmt.Sprintf("Error cleaning up build: %s\n", cleanupErr.Error()) - } - } - - buildLogger.Write([]byte(errMsg + "\n")) - - if r.telemetryEnabled { - r.logTelemetry(context.Background(), b, err) - } -} - -func (r *BuildRunner) logTelemetry(ctx context.Context, b Build, err error) { - telemetryProps := telemetry.NewBuildRunnerEventProps(ctx, b.Id, string(b.State)) - event := telemetry.BuildRunnerEventRunBuild - if err != nil { - telemetryProps["error"] = err.Error() - event = telemetry.BuildRunnerEventRunBuildError - } - telemetryError := r.telemetryService.TrackBuildRunnerEvent(event, r.Id, telemetryProps) - if telemetryError != nil { - log.Trace(telemetryError) - } -} diff --git a/pkg/build/runner_config.go b/pkg/build/runner_config.go deleted file mode 100644 index a505f44f55..0000000000 --- a/pkg/build/runner_config.go +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package build - -import ( - "encoding/json" - "fmt" - "os" - "path/filepath" - - "github.com/daytonaio/daytona/cmd/daytona/config" - "github.com/google/uuid" -) - -// TODO: add lock when running interval func -// 10 second interval -const DEFAULT_POLL_INTERVAL = "*/10 * * * * *" - -type Config struct { - Id string `json:"id" validate:"required"` - Interval string `json:"interval" validate:"required"` - TelemetryEnabled bool `json:"telemetryEnabled" validate:"required"` -} // @name BuildRunnerConfig - -func GetConfig() (*Config, error) { - configFilePath, err := getConfigFilePath() - if err != nil { - return nil, err - } - - _, err = os.Stat(configFilePath) - if os.IsNotExist(err) { - c := getDefaultConfig() - - err = Save(*c) - if err != nil { - return nil, fmt.Errorf("failed to save default config file: %w", err) - } - - return c, nil - } - - if err != nil { - return nil, err - } - - var c Config - configContent, err := os.ReadFile(configFilePath) - if err != nil { - return nil, err - } - - err = json.Unmarshal(configContent, &c) - if err != nil { - return nil, err - } - - if c.Id == "" { - c.Id = uuid.NewString() - } - err = Save(c) - if err != nil { - return nil, err - } - - return &c, nil -} - -func getConfigFilePath() (string, error) { - configDir, err := GetRunnerConfigDir() - if err != nil { - return "", err - } - - return filepath.Join(configDir, "config.json"), nil -} - -func Save(c Config) error { - configFilePath, err := getConfigFilePath() - if err != nil { - return err - } - - configContent, err := json.MarshalIndent(c, "", " ") - if err != nil { - return err - } - - err = os.MkdirAll(filepath.Dir(configFilePath), 0700) - if err != nil { - return err - } - - return os.WriteFile(configFilePath, configContent, 0600) -} - -func GetRunnerConfigDir() (string, error) { - configDir, err := config.GetConfigDir() - if err != nil { - return "", err - } - - return filepath.Join(configDir, "build-runner"), nil -} - -func getDefaultConfig() *Config { - return &Config{ - Id: uuid.NewString(), - Interval: DEFAULT_POLL_INTERVAL, - TelemetryEnabled: false, - } -} diff --git a/pkg/build/runner_test.go b/pkg/build/runner_test.go deleted file mode 100644 index 47454ddbd2..0000000000 --- a/pkg/build/runner_test.go +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package build_test - -import ( - "testing" - - t_build "github.com/daytonaio/daytona/internal/testing/build" - git_mocks "github.com/daytonaio/daytona/internal/testing/git/mocks" - logger_mocks "github.com/daytonaio/daytona/internal/testing/logger/mocks" - "github.com/daytonaio/daytona/internal/testing/server/workspaces/mocks" - "github.com/daytonaio/daytona/internal/util" - "github.com/daytonaio/daytona/pkg/build" - t_gitprovider "github.com/daytonaio/daytona/pkg/build/mocks" - "github.com/daytonaio/daytona/pkg/gitprovider" - "github.com/daytonaio/daytona/pkg/logs" - "github.com/go-git/go-git/v5/plumbing/transport/http" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/suite" -) - -var gitProviderConfig = gitprovider.GitProviderConfig{ - Id: "github", - Username: "daytonaio", - Token: "", - BaseApiUrl: nil, -} - -type BuildRunnerTestSuite struct { - suite.Suite - mockBuilderFactory mocks.MockBuilderFactory - mockBuilder mocks.MockBuilder - mockScheduler mocks.MockScheduler - mockGitService git_mocks.MockGitService - loggerFactory logs.LoggerFactory - mockBuildStore build.Store - mockGitProviderConfigStore t_gitprovider.MockGitProviderConfigStore - Runner build.BuildRunner -} - -func NewBuildRunnerTestSuite() *BuildRunnerTestSuite { - return &BuildRunnerTestSuite{} -} - -func TestBuildRunner(t *testing.T) { - s := NewBuildRunnerTestSuite() - - s.mockBuilderFactory = mocks.MockBuilderFactory{} - s.mockBuilder = mocks.MockBuilder{} - s.mockScheduler = mocks.MockScheduler{} - s.mockGitProviderConfigStore = t_gitprovider.MockGitProviderConfigStore{} - - s.mockBuildStore = t_build.NewInMemoryBuildStore() - logTempDir := t.TempDir() - s.loggerFactory = logs.NewLoggerFactory(nil, &logTempDir) - - s.Runner = *build.NewBuildRunner(build.BuildRunnerInstanceConfig{ - Interval: "0 */5 * * * *", - Scheduler: &s.mockScheduler, - BuildRunnerId: "1", - BuildStore: s.mockBuildStore, - GitProviderStore: &s.mockGitProviderConfigStore, - BuilderFactory: &s.mockBuilderFactory, - LoggerFactory: s.loggerFactory, - TelemetryEnabled: false, - }) - - suite.Run(t, s) -} - -func (s *BuildRunnerTestSuite) SetupTest() { - err := s.mockBuildStore.Save(mocks.MockBuild) - if err != nil { - s.T().Fatal(err) - } -} - -func (s *BuildRunnerTestSuite) TestStart() { - s.mockScheduler.On("AddFunc", mock.Anything, mock.Anything).Return(nil) - s.mockScheduler.On("Start").Return() - - require := s.Require() - - err := s.Runner.Start() - require.NoError(err) - - s.mockScheduler.AssertExpectations(s.T()) -} - -func (s *BuildRunnerTestSuite) TestStop() { - s.mockScheduler.On("Stop").Return() - - s.Runner.Stop() - - s.mockScheduler.AssertExpectations(s.T()) -} - -// TODO FIXME: Need to figure out how to test the RunBuildProcess goroutine -func (s *BuildRunnerTestSuite) TestRun() { - s.T().Skip("Need to figure out how to test the runBuildProcess goroutine") -} - -func (s *BuildRunnerTestSuite) TestRunBuildProcess() { - pendingBuild := *mocks.MockBuild - s.mockGitProviderConfigStore.On("ListConfigsForUrl", pendingBuild.Repository.Url).Return([]*gitprovider.GitProviderConfig{&gitProviderConfig}, nil) - s.mockGitService.On("CloneRepository", pendingBuild.Repository, &http.BasicAuth{ - Username: gitProviderConfig.Username, - }).Return(nil) - - mockGitService := git_mocks.NewMockGitService() - mockGitService.On("CloneRepository", pendingBuild.Repository, &http.BasicAuth{ - Username: gitProviderConfig.Username, - }).Return(nil) - - runningBuild := *mocks.MockBuild - runningBuild.State = build.BuildStateRunning - s.mockBuilder.On("Build", runningBuild).Return("image", "user", nil) - - successBuild := *mocks.MockBuild - successBuild.State = build.BuildStateSuccess - successBuild.Image = util.Pointer("image") - successBuild.User = util.Pointer("user") - s.mockBuilder.On("Publish", successBuild).Return(nil) - - s.mockBuilder.On("CleanUp").Return(nil) - - mockLogger := logger_mocks.NewMockLogger() - mockLogger.On("Write", mock.Anything).Return(0, nil) - - s.Runner.RunBuildProcess(build.BuildProcessConfig{ - Builder: &s.mockBuilder, - BuildLogger: mockLogger, - Build: mocks.MockBuild, - ProjectDir: "", - GitService: mockGitService, - Wg: nil, - }) - - mockLogger.AssertExpectations(s.T()) - s.mockBuilder.AssertExpectations(s.T()) - s.mockGitProviderConfigStore.AssertExpectations(s.T()) - - s.Require().Equal(mocks.MockBuild.Image, util.Pointer("image")) - s.Require().Equal(mocks.MockBuild.User, util.Pointer("user")) - s.Require().Equal(mocks.MockBuild.State, build.BuildStatePublished) -} diff --git a/pkg/build/store.go b/pkg/build/store.go deleted file mode 100644 index 04fbf9b07f..0000000000 --- a/pkg/build/store.go +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package build - -import ( - "errors" - - "github.com/daytonaio/daytona/pkg/workspace/project/buildconfig" -) - -type Store interface { - Find(filter *Filter) (*Build, error) - List(filter *Filter) ([]*Build, error) - Save(build *Build) error - Delete(id string) error -} - -var ( - ErrBuildNotFound = errors.New("build not found") -) - -func IsBuildNotFound(err error) bool { - return err.Error() == ErrBuildNotFound.Error() -} - -type Filter struct { - Id *string - States *[]BuildState - PrebuildIds *[]string - GetNewest *bool - BuildConfig *buildconfig.BuildConfig - RepositoryUrl *string - Branch *string - EnvVars *map[string]string -} - -func (f *Filter) StatesToInterface() []interface{} { - args := make([]interface{}, len(*f.States)) - for i, v := range *f.States { - args[i] = v - } - return args -} - -func (f *Filter) PrebuildIdsToInterface() []interface{} { - args := make([]interface{}, len(*f.PrebuildIds)) - for i, v := range *f.PrebuildIds { - args[i] = v - } - return args -} diff --git a/pkg/cmd/agent/agent.go b/pkg/cmd/agent/agent.go index d45061ecc0..6682cc9cd5 100644 --- a/pkg/cmd/agent/agent.go +++ b/pkg/cmd/agent/agent.go @@ -6,24 +6,31 @@ package agent import ( + "context" "fmt" "io" "os" "path/filepath" "github.com/daytonaio/daytona/cmd/daytona/config" + apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" + "github.com/daytonaio/daytona/internal/util/apiclient/conversion" "github.com/daytonaio/daytona/pkg/agent" agent_config "github.com/daytonaio/daytona/pkg/agent/config" "github.com/daytonaio/daytona/pkg/agent/ssh" "github.com/daytonaio/daytona/pkg/agent/tailscale" "github.com/daytonaio/daytona/pkg/agent/toolbox" + "github.com/daytonaio/daytona/pkg/apiclient" + "github.com/daytonaio/daytona/pkg/common" + "github.com/daytonaio/daytona/pkg/docker" "github.com/daytonaio/daytona/pkg/git" - "github.com/daytonaio/daytona/pkg/workspace/project" + "github.com/daytonaio/daytona/pkg/models" log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" ) -var hostModeFlag bool +var targetModeFlag bool var AgentCmd = &cobra.Command{ Use: "agent", @@ -32,34 +39,47 @@ var AgentCmd = &cobra.Command{ RunE: func(cmd *cobra.Command, args []string) error { setLogLevel() - agentMode := agent_config.ModeProject + agentMode := agent_config.ModeWorkspace - if hostModeFlag { - agentMode = agent_config.ModeHost + if targetModeFlag { + agentMode = agent_config.ModeTarget } c, err := agent_config.GetConfig(agentMode) if err != nil { return err } - c.ProjectDir = filepath.Join(os.Getenv("HOME"), c.ProjectName) + + telemetryEnabled := os.Getenv("DAYTONA_TELEMETRY_ENABLED") == "true" + + var ws *models.Workspace + c.WorkspaceDir = os.Getenv("HOME") + + if agentMode == agent_config.ModeWorkspace { + ws, err = getWorkspace(c, telemetryEnabled) + if err != nil { + return err + } + c.WorkspaceDir = filepath.Join(os.Getenv("HOME"), ws.WorkspaceFolderName()) + } configDir, err := config.GetConfigDir() if err != nil { return err } - if projectDir := os.Getenv("DAYTONA_PROJECT_DIR"); projectDir != "" { - c.ProjectDir = projectDir + if workspaceDir := os.Getenv("DAYTONA_WORKSPACE_DIR"); workspaceDir != "" { + c.WorkspaceDir = workspaceDir } - if _, err := os.Stat(c.ProjectDir); os.IsNotExist(err) { - if err := os.MkdirAll(c.ProjectDir, 0755); err != nil { - return fmt.Errorf("failed to create project directory: %w", err) + if _, err := os.Stat(c.WorkspaceDir); os.IsNotExist(err) { + if err := os.MkdirAll(c.WorkspaceDir, 0755); err != nil { + return fmt.Errorf("failed to create workspace directory: %w", err) } } gitLogWriter := io.MultiWriter(os.Stdout) + dockerCredHelperLogWriter := io.MultiWriter(os.Stdout) var agentLogWriter io.Writer if c.LogFilePath != nil { logFile, err := os.OpenFile(*c.LogFilePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) @@ -68,32 +88,37 @@ var AgentCmd = &cobra.Command{ } defer logFile.Close() gitLogWriter = io.MultiWriter(os.Stdout, logFile) + dockerCredHelperLogWriter = io.MultiWriter(os.Stdout, logFile) agentLogWriter = logFile } git := &git.Service{ - ProjectDir: c.ProjectDir, + WorkspaceDir: c.WorkspaceDir, GitConfigFileName: filepath.Join(os.Getenv("HOME"), ".gitconfig"), LogWriter: gitLogWriter, } + dockerCredHelper := &docker.DockerCredHelper{ + DockerConfigFileName: filepath.Join(os.Getenv("HOME"), ".docker", "config.json"), + LogWriter: dockerCredHelperLogWriter, + HomeDir: os.Getenv("HOME"), + } + sshServer := &ssh.Server{ - ProjectDir: c.ProjectDir, - DefaultProjectDir: os.Getenv("HOME"), + WorkspaceDir: c.WorkspaceDir, + DefaultWorkspaceDir: os.Getenv("HOME"), } - tailscaleHostname := project.GetProjectHostname(c.WorkspaceId, c.ProjectName) - if hostModeFlag { - tailscaleHostname = c.WorkspaceId + tailscaleHostname := common.GetTailscaleHostname(c.TargetId) + if agentMode == agent_config.ModeWorkspace { + tailscaleHostname = common.GetTailscaleHostname(ws.Id) } toolBoxServer := &toolbox.Server{ - ProjectDir: c.ProjectDir, - ConfigDir: configDir, + WorkspaceDir: c.WorkspaceDir, + ConfigDir: configDir, } - telemetryEnabled := os.Getenv("DAYTONA_TELEMETRY_ENABLED") == "true" - tailscaleServer := &tailscale.Server{ Hostname: tailscaleHostname, Server: c.Server, @@ -104,11 +129,13 @@ var AgentCmd = &cobra.Command{ agent := agent.Agent{ Config: c, Git: git, + DockerCredHelper: dockerCredHelper, Ssh: sshServer, Toolbox: toolBoxServer, Tailscale: tailscaleServer, LogWriter: agentLogWriter, TelemetryEnabled: telemetryEnabled, + Workspace: ws, } return agent.Start() @@ -116,7 +143,7 @@ var AgentCmd = &cobra.Command{ } func init() { - AgentCmd.Flags().BoolVar(&hostModeFlag, "host", false, "Run the agent in host mode") + AgentCmd.Flags().BoolVar(&targetModeFlag, "target", false, "Run the agent in target mode") AgentCmd.AddCommand(logsCmd) } @@ -133,3 +160,19 @@ func setLogLevel() { log.SetLevel(log.InfoLevel) } } + +func getWorkspace(c *agent_config.Config, telemetryEnabled bool) (*models.Workspace, error) { + ctx := context.Background() + + apiClient, err := apiclient_util.GetAgentApiClient(c.Server.ApiUrl, c.Server.ApiKey, c.ClientId, telemetryEnabled) + if err != nil { + return nil, err + } + + workspace, res, err := apiClient.WorkspaceAPI.FindWorkspace(ctx, c.WorkspaceId).Execute() + if err != nil { + return nil, apiclient_util.HandleErrorResponse(res, err) + } + + return conversion.Convert[apiclient.WorkspaceDTO, models.Workspace](workspace) +} diff --git a/pkg/cmd/agent/logs.go b/pkg/cmd/agent/logs.go index 219aff530a..399b87584e 100644 --- a/pkg/cmd/agent/logs.go +++ b/pkg/cmd/agent/logs.go @@ -10,16 +10,18 @@ import ( "io" "os" - "github.com/daytonaio/daytona/internal/util" "github.com/daytonaio/daytona/pkg/agent/config" + "github.com/daytonaio/daytona/pkg/cmd/common" + "github.com/daytonaio/daytona/pkg/logs" "github.com/spf13/cobra" ) var followFlag bool var logsCmd = &cobra.Command{ - Use: "logs", - Short: "Output Daytona Agent logs", + Use: "logs", + Short: "Output Daytona Agent logs", + Aliases: common.GetAliases("logs"), RunE: func(cmd *cobra.Command, args []string) error { logFilePath := config.GetLogFilePath() @@ -36,7 +38,7 @@ var logsCmd = &cobra.Command{ msgChan := make(chan []byte) errChan := make(chan error) - go util.ReadLog(context.Background(), file, followFlag, msgChan, errChan) + go logs.ReadLog(context.Background(), file, followFlag, msgChan, errChan) for { select { diff --git a/pkg/cmd/agentmode/agent_mode.go b/pkg/cmd/agentmode/agent_mode.go new file mode 100644 index 0000000000..187d9c3dee --- /dev/null +++ b/pkg/cmd/agentmode/agent_mode.go @@ -0,0 +1,74 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package agentmode + +import ( + "os" + "time" + + "github.com/daytonaio/daytona/cmd/daytona/config" + "github.com/daytonaio/daytona/internal/util" + cmd "github.com/daytonaio/daytona/pkg/cmd" + . "github.com/daytonaio/daytona/pkg/cmd/agent" + + "github.com/spf13/cobra" +) + +var targetId = "" +var workspaceId = "" + +var agentModeRootCmd = &cobra.Command{ + Use: "daytona", + Short: "Daytona is a Dev Environment Manager", + Long: "Daytona is a Dev Environment Manager", + DisableAutoGenTag: true, + SilenceUsage: true, + SilenceErrors: true, + RunE: func(cmd *cobra.Command, args []string) error { + return cmd.Help() + }, +} + +func Execute() error { + cmd.SetupRootCommand(agentModeRootCmd) + agentModeRootCmd.AddGroup(&cobra.Group{ID: util.TARGET_GROUP, Title: "Workspace & Target"}) + agentModeRootCmd.AddCommand(gitCredCmd) + agentModeRootCmd.AddCommand(dockerCredCmd) + agentModeRootCmd.AddCommand(AgentCmd) + agentModeRootCmd.AddCommand(infoCmd) + agentModeRootCmd.AddCommand(portForwardCmd) + agentModeRootCmd.AddCommand(exposeCmd) + agentModeRootCmd.AddCommand(logsCmd) + + clientId := config.GetClientId() + telemetryEnabled := config.TelemetryEnabled() + startTime := time.Now() + + command, flags, isComplete, err := cmd.PreRun(agentModeRootCmd, os.Args[1:], telemetryEnabled, clientId, startTime) + if err != nil { + return err + } + + err = agentModeRootCmd.Execute() + + endTime := time.Now() + if !isComplete { + cmd.PostRun(command, err, clientId, startTime, endTime, flags) + } + + return err +} + +func init() { + if targetIdEnv := os.Getenv("DAYTONA_TARGET_ID"); targetIdEnv != "" { + targetId = targetIdEnv + } + if workspaceIdEnv := os.Getenv("DAYTONA_WORKSPACE_ID"); workspaceIdEnv != "" { + workspaceId = workspaceIdEnv + } +} + +func isWorkspaceAgentMode() bool { + return workspaceId != "" +} diff --git a/pkg/cmd/agentmode/docker_cred.go b/pkg/cmd/agentmode/docker_cred.go new file mode 100644 index 0000000000..1b7f491bc8 --- /dev/null +++ b/pkg/cmd/agentmode/docker_cred.go @@ -0,0 +1,57 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package agentmode + +import ( + "context" + "fmt" + "io" + "os" + + "github.com/daytonaio/daytona/internal/util/apiclient" + "github.com/goccy/go-json" + "github.com/spf13/cobra" +) + +type Credentials struct { + Username string `json:"Username"` + Secret string `json:"Secret"` +} + +var dockerCredCmd = &cobra.Command{ + Use: "docker-cred get", + Hidden: true, + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.Background() + + input, err := io.ReadAll(os.Stdin) + if err != nil { + return err + } + + apiClient, err := apiclient.GetApiClient(nil) + if err != nil { + return err + } + + cr, _, err := apiClient.ContainerRegistryAPI.FindContainerRegistry(ctx, string(input)).WorkspaceId(workspaceId).Execute() + if err != nil { + os.Exit(1) + } + + creds := Credentials{ + Username: cr.Username, + Secret: cr.Password, + } + + data, err := json.MarshalIndent(creds, "", " ") + if err != nil { + return err + } + + fmt.Println(string(data)) + + return nil + }, +} diff --git a/pkg/cmd/workspacemode/expose.go b/pkg/cmd/agentmode/expose.go similarity index 89% rename from pkg/cmd/workspacemode/expose.go rename to pkg/cmd/agentmode/expose.go index ef95e27242..66568514b5 100644 --- a/pkg/cmd/workspacemode/expose.go +++ b/pkg/cmd/agentmode/expose.go @@ -1,7 +1,7 @@ // Copyright 2024 Daytona Platforms Inc. // SPDX-License-Identifier: Apache-2.0 -package workspacemode +package agentmode import ( "fmt" @@ -17,9 +17,9 @@ import ( var exposeCmd = &cobra.Command{ Use: "expose [PORT]", - Short: "Expose a local port over stdout - Used by the Daytona CLI to make direct connections to the project", + Short: "Expose a local port over stdout - Used by the Daytona CLI to make direct connections to the workspace", Args: cobra.ExactArgs(1), - GroupID: util.WORKSPACE_GROUP, + GroupID: util.TARGET_GROUP, RunE: func(cmd *cobra.Command, args []string) error { port, err := strconv.Atoi(args[0]) if err != nil { diff --git a/pkg/cmd/workspacemode/forward.go b/pkg/cmd/agentmode/forward.go similarity index 74% rename from pkg/cmd/workspacemode/forward.go rename to pkg/cmd/agentmode/forward.go index 3bfc645953..181750f78d 100644 --- a/pkg/cmd/workspacemode/forward.go +++ b/pkg/cmd/agentmode/forward.go @@ -1,12 +1,13 @@ // Copyright 2024 Daytona Platforms Inc. // SPDX-License-Identifier: Apache-2.0 -package workspacemode +package agentmode import ( "strconv" "github.com/daytonaio/daytona/internal/util" + "github.com/daytonaio/daytona/pkg/cmd/common" defaultPortForwardCmd "github.com/daytonaio/daytona/pkg/cmd/ports" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -16,7 +17,8 @@ var portForwardCmd = &cobra.Command{ Use: "forward [PORT]", Short: "Forward a port publicly via an URL", Args: cobra.ExactArgs(1), - GroupID: util.WORKSPACE_GROUP, + GroupID: util.TARGET_GROUP, + Aliases: common.GetAliases("forward"), RunE: func(cmd *cobra.Command, args []string) error { port, err := strconv.Atoi(args[0]) if err != nil { @@ -25,7 +27,7 @@ var portForwardCmd = &cobra.Command{ errChan := make(chan error) go func() { - errChan <- defaultPortForwardCmd.ForwardPublicPort(workspaceId, projectName, uint16(port), uint16(port)) + errChan <- defaultPortForwardCmd.ForwardPublicPort(targetId, workspaceId, uint16(port), uint16(port)) }() for { diff --git a/pkg/cmd/workspacemode/git_cred.go b/pkg/cmd/agentmode/git_cred.go similarity index 79% rename from pkg/cmd/workspacemode/git_cred.go rename to pkg/cmd/agentmode/git_cred.go index 572d9659f8..c33a6f149a 100644 --- a/pkg/cmd/workspacemode/git_cred.go +++ b/pkg/cmd/agentmode/git_cred.go @@ -1,7 +1,7 @@ // Copyright 2024 Daytona Platforms Inc. // SPDX-License-Identifier: Apache-2.0 -package workspacemode +package agentmode import ( "bufio" @@ -37,22 +37,13 @@ var gitCredCmd = &cobra.Command{ return err } - workspace, res, err := apiClient.WorkspaceAPI.GetWorkspace(ctx, workspaceId).Execute() + workspace, res, err := apiClient.WorkspaceAPI.FindWorkspace(ctx, workspaceId).Execute() if err != nil { return apiclient.HandleErrorResponse(res, err) } - var gitProviderConfigId *string - - for _, project := range workspace.Projects { - if project.Name == projectName { - gitProviderConfigId = project.GitProviderConfigId - break - } - } - - if gitProviderConfigId != nil { - gitProvider, _, _ := apiClient.GitProviderAPI.GetGitProvider(ctx, *gitProviderConfigId).Execute() + if workspace.GitProviderConfigId != nil { + gitProvider, _, _ := apiClient.GitProviderAPI.FindGitProvider(ctx, *workspace.GitProviderConfigId).Execute() if gitProvider != nil { fmt.Println("username=" + gitProvider.Username) fmt.Println("password=" + gitProvider.Token) diff --git a/pkg/cmd/agentmode/info.go b/pkg/cmd/agentmode/info.go new file mode 100644 index 0000000000..70a13042d7 --- /dev/null +++ b/pkg/cmd/agentmode/info.go @@ -0,0 +1,75 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package agentmode + +import ( + "github.com/daytonaio/daytona/internal/util" + apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" + "github.com/daytonaio/daytona/pkg/cmd/common" + "github.com/daytonaio/daytona/pkg/cmd/format" + target_views "github.com/daytonaio/daytona/pkg/views/target/info" + workspaces_views "github.com/daytonaio/daytona/pkg/views/workspace/info" + "github.com/spf13/cobra" +) + +var infoCmd = &cobra.Command{ + Use: "info", + Short: "Show resource info", + Args: cobra.ExactArgs(0), + GroupID: util.TARGET_GROUP, + Aliases: common.GetAliases("info"), + RunE: func(cmd *cobra.Command, args []string) error { + if isWorkspaceAgentMode() { + return runWorkspaceInfo() + } + + return runTargetInfo() + }, +} + +func init() { + format.RegisterFormatFlag(infoCmd) +} + +func runWorkspaceInfo() error { + workspace, _, err := apiclient_util.GetWorkspace(workspaceId) + if err != nil { + return err + } + + if workspace == nil { + return nil + } + + if format.FormatFlag != "" { + formattedData := format.NewFormatter(workspace) + formattedData.Print() + return nil + } + + workspaces_views.Render(workspace, "", false) + + return nil +} + +func runTargetInfo() error { + target, _, err := apiclient_util.GetTarget(targetId) + if err != nil { + return err + } + + if target == nil { + return nil + } + + if format.FormatFlag != "" { + formattedData := format.NewFormatter(target) + formattedData.Print() + return nil + } + + target_views.Render(target, false) + + return nil +} diff --git a/pkg/cmd/agentmode/logs.go b/pkg/cmd/agentmode/logs.go new file mode 100644 index 0000000000..7b9c07f8da --- /dev/null +++ b/pkg/cmd/agentmode/logs.go @@ -0,0 +1,78 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package agentmode + +import ( + "context" + + "github.com/daytonaio/daytona/internal/util" + apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" + "github.com/daytonaio/daytona/pkg/agent/config" + "github.com/daytonaio/daytona/pkg/cmd/common" + cmd_common "github.com/daytonaio/daytona/pkg/cmd/common" + "github.com/spf13/cobra" +) + +var logsCmd = &cobra.Command{ + Use: "logs", + Short: "View resource logs", + Args: cobra.NoArgs, + GroupID: util.TARGET_GROUP, + Aliases: common.GetAliases("logs"), + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.Background() + + mode := config.ModeTarget + if isWorkspaceAgentMode() { + mode = config.ModeWorkspace + } + + cfg, err := config.GetConfig(mode) + if err != nil { + return err + } + + if isWorkspaceAgentMode() { + return runWorkspaceLogs(ctx, cfg.Server.ApiUrl, cfg.Server.ApiKey) + } + + return runTargetLogs(ctx, cfg.Server.ApiUrl, cfg.Server.ApiKey) + }, +} + +func runWorkspaceLogs(ctx context.Context, serverUrl, serverApiKey string) error { + workspace, _, err := apiclient_util.GetWorkspace(workspaceId) + if err != nil { + return err + } + + cmd_common.ReadWorkspaceLogs(ctx, cmd_common.ReadLogParams{ + Id: workspace.Id, + Label: &workspace.Name, + ServerUrl: serverUrl, + ApiKey: serverApiKey, + Index: util.Pointer(0), + Follow: util.Pointer(false), + }) + + return nil +} + +func runTargetLogs(ctx context.Context, serverUrl, serverApiKey string) error { + target, _, err := apiclient_util.GetTarget(targetId) + if err != nil { + return err + } + + cmd_common.ReadTargetLogs(ctx, cmd_common.ReadLogParams{ + Id: target.Id, + Label: &target.Name, + ServerUrl: serverUrl, + ApiKey: serverApiKey, + Index: util.Pointer(0), + Follow: util.Pointer(false), + }) + + return nil +} diff --git a/pkg/cmd/apikey/api_key.go b/pkg/cmd/apikey/api_key.go index 703541bd96..8bbfb171ef 100644 --- a/pkg/cmd/apikey/api_key.go +++ b/pkg/cmd/apikey/api_key.go @@ -13,10 +13,11 @@ var ApiKeyCmd = &cobra.Command{ Short: "Api Key commands", Args: cobra.NoArgs, GroupID: util.SERVER_GROUP, + Aliases: []string{"api-keys"}, } func init() { - ApiKeyCmd.AddCommand(GenerateCmd) - ApiKeyCmd.AddCommand(revokeCmd) + ApiKeyCmd.AddCommand(createCmd) + ApiKeyCmd.AddCommand(deleteCmd) ApiKeyCmd.AddCommand(listCmd) } diff --git a/pkg/cmd/apikey/generate.go b/pkg/cmd/apikey/create.go similarity index 82% rename from pkg/cmd/apikey/generate.go rename to pkg/cmd/apikey/create.go index 52ada83072..65f66d9747 100644 --- a/pkg/cmd/apikey/generate.go +++ b/pkg/cmd/apikey/create.go @@ -12,15 +12,15 @@ import ( "github.com/daytonaio/daytona/internal/util" apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" "github.com/daytonaio/daytona/pkg/apiclient" - "github.com/daytonaio/daytona/pkg/views/apikey" + "github.com/daytonaio/daytona/pkg/cmd/common" view "github.com/daytonaio/daytona/pkg/views/apikey" ) -var GenerateCmd = &cobra.Command{ - Use: "generate [NAME]", - Short: "Generate a new API key", - Aliases: []string{"g", "new"}, +var createCmd = &cobra.Command{ + Use: "create [NAME]", + Short: "Create a new API key", Args: cobra.RangeArgs(0, 1), + Aliases: common.GetAliases("create"), RunE: func(cmd *cobra.Command, args []string) error { ctx := context.Background() var keyName string @@ -38,7 +38,7 @@ var GenerateCmd = &cobra.Command{ if len(args) == 1 { keyName = args[0] } else { - apikey.ApiKeyCreationView(&keyName, apiKeyList) + view.ApiKeyCreationView(&keyName, apiKeyList) } for _, key := range apiKeyList { @@ -47,7 +47,7 @@ var GenerateCmd = &cobra.Command{ } } - key, _, err := apiClient.ApiKeyAPI.GenerateApiKey(ctx, keyName).Execute() + key, _, err := apiClient.ApiKeyAPI.CreateApiKey(ctx, keyName).Execute() if err != nil { return apiclient_util.HandleErrorResponse(nil, err) } diff --git a/pkg/cmd/apikey/revoke.go b/pkg/cmd/apikey/delete.go similarity index 60% rename from pkg/cmd/apikey/revoke.go rename to pkg/cmd/apikey/delete.go index 8194d3c87b..38e30ff386 100644 --- a/pkg/cmd/apikey/revoke.go +++ b/pkg/cmd/apikey/delete.go @@ -11,10 +11,9 @@ import ( "github.com/charmbracelet/huh" "github.com/spf13/cobra" - "github.com/daytonaio/daytona/cmd/daytona/config" - "github.com/daytonaio/daytona/internal/apikeys" apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" "github.com/daytonaio/daytona/pkg/apiclient" + cmd_common "github.com/daytonaio/daytona/pkg/cmd/common" "github.com/daytonaio/daytona/pkg/common" "github.com/daytonaio/daytona/pkg/views" "github.com/daytonaio/daytona/pkg/views/apikey" @@ -22,30 +21,20 @@ import ( var yesFlag bool -var revokeCmd = &cobra.Command{ - Use: "revoke [NAME]", - Short: "Revoke an API key", - Aliases: []string{"r", "rm", "delete"}, +var deleteCmd = &cobra.Command{ + Use: "delete [NAME]", + Short: "Delete an API key", Args: cobra.RangeArgs(0, 1), + Aliases: cmd_common.GetAliases("delete"), RunE: func(cmd *cobra.Command, args []string) error { ctx := context.Background() - c, err := config.GetConfig() - if err != nil { - return err - } - - activeProfile, err := c.GetActiveProfile() - if err != nil { - return err - } - apiClient, err := apiclient_util.GetApiClient(nil) if err != nil { return err } - var selectedApiKey *apiclient.ApiKey + var selectedApiKey *apiclient.ApiKeyViewDTO apiKeyList, _, err := apiClient.ApiKeyAPI.ListClientApiKeys(ctx).Execute() if err != nil { @@ -71,22 +60,15 @@ var revokeCmd = &cobra.Command{ } if selectedApiKey == nil { - return errors.New("No API key selected") + return errors.New("no API key selected") } if !yesFlag { - title := fmt.Sprintf("Revoke API Key '%s'?", selectedApiKey.Name) - description := fmt.Sprintf("Are you sure you want to revoke '%s'?", selectedApiKey.Name) - if apikeys.EqualsKeyHashFromApi(activeProfile.Api.Key, selectedApiKey.KeyHash) { - title = fmt.Sprintf("Warning! API Key '%s' is attached to your active profile", selectedApiKey.Name) - description = fmt.Sprintf("Revoking '%s' will lock out your active profile from accessing the server.", selectedApiKey.Name) - } - form := huh.NewForm( huh.NewGroup( huh.NewConfirm(). - Title(title). - Description(description). + Title(fmt.Sprintf("Revoke API Key '%s'?", selectedApiKey.Name)). + Description(fmt.Sprintf("Are you sure you want to revoke '%s'?", selectedApiKey.Name)). Value(&yesFlag), ), ).WithTheme(views.GetCustomTheme()) @@ -97,8 +79,12 @@ var revokeCmd = &cobra.Command{ } } + if selectedApiKey.Current { + return errors.New("cannot revoke current API key") + } + if yesFlag { - res, err := apiClient.ApiKeyAPI.RevokeApiKey(ctx, selectedApiKey.Name).Execute() + res, err := apiClient.ApiKeyAPI.DeleteApiKey(ctx, selectedApiKey.Name).Execute() if err != nil { return apiclient_util.HandleErrorResponse(res, err) } @@ -113,5 +99,5 @@ var revokeCmd = &cobra.Command{ } func init() { - revokeCmd.Flags().BoolVarP(&yesFlag, "yes", "y", false, "Skip confirmation prompt") + deleteCmd.Flags().BoolVarP(&yesFlag, "yes", "y", false, "Skip confirmation prompt") } diff --git a/pkg/cmd/apikey/list.go b/pkg/cmd/apikey/list.go index b6375f265a..6e847ec016 100644 --- a/pkg/cmd/apikey/list.go +++ b/pkg/cmd/apikey/list.go @@ -7,6 +7,7 @@ import ( "context" "github.com/daytonaio/daytona/internal/util/apiclient" + "github.com/daytonaio/daytona/pkg/cmd/common" "github.com/daytonaio/daytona/pkg/cmd/format" "github.com/daytonaio/daytona/pkg/views/apikey" "github.com/spf13/cobra" @@ -15,7 +16,7 @@ import ( var listCmd = &cobra.Command{ Use: "list", Short: "List API keys", - Aliases: []string{"ls"}, + Aliases: common.GetAliases("list"), RunE: func(cmd *cobra.Command, args []string) error { ctx := context.Background() diff --git a/pkg/cmd/bootstrap/get_local_runner.go b/pkg/cmd/bootstrap/get_local_runner.go new file mode 100644 index 0000000000..7764ffe5f7 --- /dev/null +++ b/pkg/cmd/bootstrap/get_local_runner.go @@ -0,0 +1,377 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package bootstrap + +import ( + "context" + "fmt" + "io" + "net/url" + "os" + "path/filepath" + "strings" + + "github.com/daytonaio/daytona/internal/util" + "github.com/daytonaio/daytona/pkg/build" + "github.com/daytonaio/daytona/pkg/common" + "github.com/daytonaio/daytona/pkg/docker" + jobs_build "github.com/daytonaio/daytona/pkg/jobs/build" + jobs_runner "github.com/daytonaio/daytona/pkg/jobs/runner" + "github.com/daytonaio/daytona/pkg/jobs/target" + "github.com/daytonaio/daytona/pkg/jobs/workspace" + "github.com/daytonaio/daytona/pkg/logs" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/runner" + "github.com/daytonaio/daytona/pkg/runner/providermanager" + "github.com/daytonaio/daytona/pkg/server" + "github.com/daytonaio/daytona/pkg/server/headscale" + "github.com/daytonaio/daytona/pkg/services" + "github.com/daytonaio/daytona/pkg/stores" + "github.com/daytonaio/daytona/pkg/telemetry" + "github.com/docker/docker/client" + "github.com/docker/docker/pkg/stringid" + log "github.com/sirupsen/logrus" +) + +type LocalRunnerParams struct { + ServerConfig *server.Config + RunnerConfig *runner.Config + ConfigDir string + TelemetryService telemetry.TelemetryService +} + +type LocalJobFactoryParams struct { + ServerConfig *server.Config + ConfigDir string + TelemetryService telemetry.TelemetryService + ProviderManager providermanager.IProviderManager +} + +func GetLocalRunner(params LocalRunnerParams) (runner.IRunner, error) { + loggerFactory := logs.NewLoggerFactory(logs.LoggerFactoryConfig{LogsDir: server.GetRunnerLogsDir(params.ConfigDir)}) + + runnerLogger, err := loggerFactory.CreateLogger(common.LOCAL_RUNNER_ID, common.LOCAL_RUNNER_ID, logs.LogSourceRunner) + if err != nil { + return nil, err + } + + logger := &log.Logger{ + Out: io.MultiWriter(runnerLogger, os.Stdout), + Formatter: &log.TextFormatter{ + ForceColors: true, + }, + Hooks: make(log.LevelHooks), + Level: log.DebugLevel, + } + + jobService := server.GetInstance(nil).JobService + + providerManager, err := getProviderManager(params, logger) + if err != nil { + return nil, err + } + + jobFactoryParams := LocalJobFactoryParams{ + ServerConfig: params.ServerConfig, + ConfigDir: params.ConfigDir, + TelemetryService: params.TelemetryService, + ProviderManager: providerManager, + } + + runnerService := server.GetInstance(nil).RunnerService + + workspaceJobFactory, err := getLocalWorkspaceJobFactory(jobFactoryParams) + if err != nil { + return nil, err + } + + targetJobFactory, err := getLocalTargetJobFactory(jobFactoryParams) + if err != nil { + return nil, err + } + + buildJobFactory, err := getLocalBuildJobFactory(jobFactoryParams) + if err != nil { + return nil, err + } + + runnerJobFactory := jobs_runner.NewRunnerJobFactory(jobs_runner.RunnerJobFactoryConfig{ + TrackTelemetryEvent: func(event telemetry.Event, clientId string) error { + return params.TelemetryService.Track(event, clientId) + }, + ProviderManager: providerManager, + }) + + return runner.NewRunner(runner.RunnerConfig{ + Config: params.RunnerConfig, + Logger: logger, + ProviderManager: providerManager, + RegistryUrl: params.ServerConfig.RegistryUrl, + ListPendingJobs: func(ctx context.Context) ([]*models.Job, int, error) { + jobs, err := jobService.List(ctx, &stores.JobFilter{ + RunnerIdOrIsNil: util.Pointer(common.LOCAL_RUNNER_ID), + States: &[]models.JobState{models.JobStatePending}, + }) + return jobs, 0, err + }, + UpdateJobState: func(ctx context.Context, jobId string, state models.JobState, err error) error { + var jobErr *string + if err != nil { + jobErr = util.Pointer(err.Error()) + } + return jobService.UpdateState(ctx, jobId, services.UpdateJobStateDTO{ + State: state, + ErrorMessage: jobErr, + }) + }, + TrackTelemetryEvent: func(event telemetry.Event, clientId string) error { + return params.TelemetryService.Track(event, clientId) + }, + SetRunnerMetadata: func(ctx context.Context, runnerId string, metadata models.RunnerMetadata) error { + return runnerService.UpdateMetadata(context.Background(), runnerId, &models.RunnerMetadata{ + Uptime: uint64(metadata.Uptime), + Providers: metadata.Providers, + RunningJobs: metadata.RunningJobs, + }) + }, + WorkspaceJobFactory: workspaceJobFactory, + TargetJobFactory: targetJobFactory, + BuildJobFactory: buildJobFactory, + RunnerJobFactory: runnerJobFactory, + }), nil +} + +func getLocalWorkspaceJobFactory(params LocalJobFactoryParams) (workspace.IWorkspaceJobFactory, error) { + workspaceLogsFactory := logs.NewLoggerFactory(logs.LoggerFactoryConfig{LogsDir: server.GetWorkspaceLogsDir(params.ConfigDir)}) + + envVarService := server.GetInstance(nil).EnvironmentVariableService + + gitProviderService := server.GetInstance(nil).GitProviderService + + targetService := server.GetInstance(nil).TargetService + + workspaceService := server.GetInstance(nil).WorkspaceService + + return workspace.NewWorkspaceJobFactory(workspace.WorkspaceJobFactoryConfig{ + FindWorkspace: func(ctx context.Context, workspaceId string) (*models.Workspace, error) { + workspaceDto, err := workspaceService.Find(ctx, workspaceId, services.WorkspaceRetrievalParams{}) + if err != nil { + return nil, err + } + return &workspaceDto.Workspace, nil + }, + FindTarget: func(ctx context.Context, targetId string) (*models.Target, error) { + targetDto, err := targetService.Find(ctx, &stores.TargetFilter{IdOrName: &targetId}, services.TargetRetrievalParams{}) + if err != nil { + return nil, err + } + return &targetDto.Target, nil + }, + UpdateWorkspaceProviderMetadata: workspaceService.UpdateProviderMetadata, + FindGitProviderConfig: func(ctx context.Context, id string) (*models.GitProviderConfig, error) { + return gitProviderService.FindConfig(ctx, id) + }, + GetWorkspaceEnvironmentVariables: func(ctx context.Context, w *models.Workspace) (map[string]string, error) { + serverEnvVars, err := envVarService.Map(ctx) + if err != nil { + return nil, err + } + + return util.MergeEnvVars(serverEnvVars, w.EnvVars), nil + }, + TrackTelemetryEvent: func(event telemetry.Event, clientId string) error { + return params.TelemetryService.Track(event, clientId) + }, + LoggerFactory: workspaceLogsFactory, + ProviderManager: params.ProviderManager, + BuilderImage: params.ServerConfig.BuilderImage, + }), nil +} + +func getLocalTargetJobFactory(params LocalJobFactoryParams) (target.ITargetJobFactory, error) { + loggerFactory := logs.NewLoggerFactory(logs.LoggerFactoryConfig{LogsDir: server.GetTargetLogsDir(params.ConfigDir)}) + + targetService := server.GetInstance(nil).TargetService + + return target.NewTargetJobFactory(target.TargetJobFactoryConfig{ + FindTarget: func(ctx context.Context, targetId string) (*models.Target, error) { + targetDto, err := targetService.Find(ctx, &stores.TargetFilter{IdOrName: &targetId}, services.TargetRetrievalParams{}) + if err != nil { + return nil, err + } + return &targetDto.Target, nil + }, + HandleSuccessfulCreation: func(ctx context.Context, targetId string) error { + return targetService.HandleSuccessfulCreation(ctx, targetId) + }, + UpdateTargetProviderMetadata: targetService.UpdateProviderMetadata, + TrackTelemetryEvent: func(event telemetry.Event, clientId string) error { + return params.TelemetryService.Track(event, clientId) + }, + LoggerFactory: loggerFactory, + ProviderManager: params.ProviderManager, + }), nil +} + +func getLocalBuildJobFactory(params LocalJobFactoryParams) (jobs_build.IBuildJobFactory, error) { + buildLogsFactory := logs.NewLoggerFactory(logs.LoggerFactoryConfig{LogsDir: server.GetBuildLogsDir(params.ConfigDir)}) + + cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) + if err != nil { + return nil, err + } + + dockerClient := docker.NewDockerClient(docker.DockerClientConfig{ + ApiClient: cli, + }) + + buildService := server.GetInstance(nil).BuildService + + buildImageNamespace := params.ServerConfig.BuildImageNamespace + if buildImageNamespace != "" { + buildImageNamespace = fmt.Sprintf("/%s", buildImageNamespace) + } + buildImageNamespace = strings.TrimSuffix(buildImageNamespace, "/") + + var builderRegistry *models.ContainerRegistry + + envVarService := server.GetInstance(nil).EnvironmentVariableService + + envVars, err := envVarService.Map(context.Background()) + if err != nil { + builderRegistry = &models.ContainerRegistry{ + Server: params.ServerConfig.BuilderRegistryServer, + } + } else { + builderRegistry = envVars.FindContainerRegistry(params.ServerConfig.BuilderRegistryServer) + } + + if builderRegistry == nil { + builderRegistry = &models.ContainerRegistry{ + Server: util.GetFrpcRegistryDomain(params.ServerConfig.Id, params.ServerConfig.Frps.Domain), + } + } + + _, containerRegistries := common.ExtractContainerRegistryFromEnvVars(envVars) + + return jobs_build.NewBuildJobFactory(jobs_build.BuildJobFactoryConfig{ + FindBuild: func(ctx context.Context, buildId string) (*services.BuildDTO, error) { + return buildService.Find(ctx, &services.BuildFilter{ + StoreFilter: stores.BuildFilter{ + Id: &buildId, + }, + }) + }, + ListSuccessfulBuilds: func(ctx context.Context, repoUrl string) ([]*models.Build, error) { + buildDtos, err := buildService.List(ctx, &services.BuildFilter{ + StateNames: &[]models.ResourceStateName{models.ResourceStateNameRunSuccessful}, + StoreFilter: stores.BuildFilter{ + RepositoryUrl: &repoUrl, + }, + }) + if err != nil { + return nil, err + } + + var builds []*models.Build + for _, buildDto := range buildDtos { + builds = append(builds, &buildDto.Build) + } + return builds, nil + }, + ListConfigsForUrl: func(ctx context.Context, repoUrl string) ([]*models.GitProviderConfig, error) { + return server.GetInstance(nil).GitProviderService.ListConfigsForUrl(ctx, repoUrl) + }, + CheckImageExists: func(ctx context.Context, image string) bool { + _, _, err = cli.ImageInspectWithRaw(context.Background(), image) + return err == nil + }, + DeleteImage: func(ctx context.Context, image string, force bool) error { + return dockerClient.DeleteImage(image, force, nil) + }, + TrackTelemetryEvent: func(event telemetry.Event, clientId string) error { + return params.TelemetryService.Track(event, clientId) + }, + LoggerFactory: buildLogsFactory, + BuilderFactory: build.NewBuilderFactory(build.BuilderFactoryConfig{ + ContainerRegistries: containerRegistries, + Image: params.ServerConfig.BuilderImage, + BuildImageContainerRegistry: builderRegistry, + + BuildImageNamespace: buildImageNamespace, + LoggerFactory: buildLogsFactory, + DefaultWorkspaceImage: params.ServerConfig.DefaultWorkspaceImage, + DefaultWorkspaceUser: params.ServerConfig.DefaultWorkspaceUser, + }), + BasePath: filepath.Join(params.ConfigDir, "builds"), + }), nil +} + +func getProviderManager(params LocalRunnerParams, logger *log.Logger) (providermanager.IProviderManager, error) { + headscaleServer := headscale.NewHeadscaleServer(&headscale.HeadscaleServerConfig{ + ServerId: params.ServerConfig.Id, + FrpsDomain: params.ServerConfig.Frps.Domain, + FrpsProtocol: params.ServerConfig.Frps.Protocol, + HeadscalePort: params.ServerConfig.HeadscalePort, + ConfigDir: filepath.Join(params.ConfigDir, "headscale"), + Frps: params.ServerConfig.Frps, + }) + err := headscaleServer.Init() + if err != nil { + return nil, err + } + + headscaleUrl := util.GetFrpcHeadscaleUrl(params.ServerConfig.Frps.Protocol, params.ServerConfig.Id, params.ServerConfig.Frps.Domain) + binaryUrl, _ := url.JoinPath(util.GetFrpcApiUrl(params.ServerConfig.Frps.Protocol, params.ServerConfig.Id, params.ServerConfig.Frps.Domain), "binary", "script") + + targetConfigService := server.GetInstance(nil).TargetConfigService + targetService := server.GetInstance(nil).TargetService + + return providermanager.GetProviderManager(&providermanager.ProviderManagerConfig{ + TargetLogsDir: server.GetTargetLogsDir(params.ConfigDir), + WorkspaceLogsDir: server.GetWorkspaceLogsDir(params.ConfigDir), + Logger: logger, + ApiUrl: util.GetFrpcApiUrl(params.ServerConfig.Frps.Protocol, params.ServerConfig.Id, params.ServerConfig.Frps.Domain), + RunnerName: params.RunnerConfig.Name, + RunnerId: params.RunnerConfig.Id, + DaytonaDownloadUrl: binaryUrl, + ServerUrl: headscaleUrl, + BaseDir: params.RunnerConfig.ProvidersDir, + CreateProviderNetworkKey: func(ctx context.Context, providerName string) (string, error) { + return headscaleServer.CreateAuthKey(headscale.HEADSCALE_USERNAME) + }, + ServerPort: params.ServerConfig.HeadscalePort, + ApiPort: params.ServerConfig.ApiPort, + GetTargetConfigMap: func(ctx context.Context) (map[string]*models.TargetConfig, error) { + return targetConfigService.Map(ctx) + }, + CreateTargetConfig: func(ctx context.Context, name, options string, providerInfo models.ProviderInfo) error { + tc, err := targetConfigService.Create(ctx, services.CreateTargetConfigDTO{ + Name: name, + Options: options, + ProviderInfo: providerInfo, + }) + + if err != nil { + return err + } + + if providerInfo.Name == "docker-provider" { + id := stringid.GenerateRandomID() + id = stringid.TruncateID(id) + + _, err := targetService.Create(ctx, services.CreateTargetDTO{ + TargetConfigId: tc.Id, + Name: name, + Id: id, + }) + if err != nil { + log.Error(err) + } + } + + return nil + }, + }), nil +} diff --git a/pkg/cmd/bootstrap/get_remote_runner.go b/pkg/cmd/bootstrap/get_remote_runner.go new file mode 100644 index 0000000000..7986fd7acb --- /dev/null +++ b/pkg/cmd/bootstrap/get_remote_runner.go @@ -0,0 +1,479 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package bootstrap + +import ( + "context" + "errors" + "fmt" + "io" + "net/url" + "os" + "path/filepath" + "strings" + + "github.com/daytonaio/daytona/internal/util" + "github.com/daytonaio/daytona/internal/util/apiclient/conversion" + "github.com/daytonaio/daytona/pkg/apiclient" + "github.com/daytonaio/daytona/pkg/build" + "github.com/daytonaio/daytona/pkg/common" + "github.com/daytonaio/daytona/pkg/docker" + jobs_build "github.com/daytonaio/daytona/pkg/jobs/build" + jobs_runner "github.com/daytonaio/daytona/pkg/jobs/runner" + "github.com/daytonaio/daytona/pkg/jobs/target" + "github.com/daytonaio/daytona/pkg/jobs/workspace" + "github.com/daytonaio/daytona/pkg/logs" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/runner/providermanager" + "github.com/daytonaio/daytona/pkg/services" + "github.com/daytonaio/daytona/pkg/telemetry" + "github.com/docker/docker/client" + log "github.com/sirupsen/logrus" + + "github.com/daytonaio/daytona/pkg/runner" +) + +type RemoteRunnerParams struct { + ApiClient *apiclient.APIClient + ServerConfig *apiclient.ServerConfig + RunnerConfig *runner.Config + ConfigDir string + LogWriter io.Writer + TelemetryService telemetry.TelemetryService +} + +type RemoteJobFactoryParams struct { + ApiClient *apiclient.APIClient + ServerConfig *apiclient.ServerConfig + RunnerConfig *runner.Config + ConfigDir string + TelemetryService telemetry.TelemetryService + ProviderManager providermanager.IProviderManager +} + +func GetRemoteRunner(params RemoteRunnerParams) (runner.IRunner, error) { + runnerLogsDir := runner.GetLogsDir(params.ConfigDir) + loggerFactory := logs.NewLoggerFactory(logs.LoggerFactoryConfig{ + LogsDir: runnerLogsDir, + ApiUrl: ¶ms.RunnerConfig.ServerApiUrl, + ApiKey: ¶ms.RunnerConfig.ServerApiKey, + ApiBasePath: &logs.ApiBasePathRunner, + }) + + runnerLogger, err := loggerFactory.CreateLogger(params.RunnerConfig.Id, params.RunnerConfig.Name, logs.LogSourceRunner) + if err != nil { + return nil, err + } + + logger := &log.Logger{ + Out: io.MultiWriter(runnerLogger, os.Stdout), + Formatter: &log.TextFormatter{ + ForceColors: true, + }, + Hooks: make(log.LevelHooks), + Level: log.DebugLevel, + } + + providerManager := getRemoteProviderManager(params, logger) + + jobFactoryParams := RemoteJobFactoryParams{ + ApiClient: params.ApiClient, + ServerConfig: params.ServerConfig, + RunnerConfig: params.RunnerConfig, + ConfigDir: params.ConfigDir, + TelemetryService: params.TelemetryService, + ProviderManager: providerManager, + } + + workspaceJobFactory, err := getRemoteWorkspaceJobFactory(jobFactoryParams) + if err != nil { + return nil, err + } + + targetJobFactory, err := getRemoteTargetJobFactory(jobFactoryParams) + if err != nil { + return nil, err + } + + buildJobFactory, err := getRemoteBuildJobFactory(jobFactoryParams) + if err != nil { + return nil, err + } + + runnerJobFactory := jobs_runner.NewRunnerJobFactory(jobs_runner.RunnerJobFactoryConfig{ + TrackTelemetryEvent: func(event telemetry.Event, clientId string) error { + return params.TelemetryService.Track(event, clientId) + }, + ProviderManager: providerManager, + }) + + return runner.NewRunner(runner.RunnerConfig{ + Config: params.RunnerConfig, + Logger: logger, + ProviderManager: providerManager, + RegistryUrl: params.ServerConfig.RegistryUrl, + ListPendingJobs: func(ctx context.Context) ([]*models.Job, int, error) { + jobs, res, err := params.ApiClient.RunnerAPI.ListRunnerJobs(ctx, params.RunnerConfig.Id).Execute() + if err != nil { + statusCode := -1 + if res != nil { + statusCode = res.StatusCode + } + return nil, statusCode, err + } + + var response []*models.Job + for _, job := range jobs { + response = append(response, &models.Job{ + Id: job.Id, + ResourceId: job.ResourceId, + RunnerId: job.RunnerId, + ResourceType: models.ResourceType(job.ResourceType), + State: models.JobState(job.State), + Action: models.JobAction(job.Action), + Metadata: job.Metadata, + Error: job.Error, + // TODO: Convert + // CreatedAt: parseTime(job.CreatedAt), + // UpdatedAt: parseTime(job.UpdatedAt), + }) + } + return response, res.StatusCode, nil + }, + TrackTelemetryEvent: func(event telemetry.Event, clientId string) error { + return params.TelemetryService.Track(event, clientId) + }, + UpdateJobState: func(ctx context.Context, jobId string, state models.JobState, jobError error) error { + var jobErr *string + if jobError != nil { + jobErr = util.Pointer(jobError.Error()) + } + _, err := params.ApiClient.RunnerAPI.UpdateJobState(ctx, params.RunnerConfig.Id, jobId).UpdateJobState(apiclient.UpdateJobState{ + State: apiclient.JobState(state), + ErrorMessage: jobErr, + }).Execute() + return err + }, + SetRunnerMetadata: func(ctx context.Context, runnerId string, metadata models.RunnerMetadata) error { + var providers []apiclient.ProviderInfo + + for _, provider := range metadata.Providers { + providerInfoDto, err := conversion.Convert[models.ProviderInfo, apiclient.ProviderInfo](&provider) + if err != nil { + return err + } + if providerInfoDto == nil { + continue + } + + providers = append(providers, *providerInfoDto) + } + + runnerMetadata := apiclient.UpdateRunnerMetadataDTO{ + Uptime: int32(metadata.Uptime), + Providers: providers, + } + + if metadata.RunningJobs != nil { + runnerMetadata.RunningJobs = util.Pointer(int32(*metadata.RunningJobs)) + } + + _, err := params.ApiClient.RunnerAPI.UpdateRunnerMetadata(ctx, runnerId).RunnerMetadata(runnerMetadata).Execute() + return err + }, + WorkspaceJobFactory: workspaceJobFactory, + TargetJobFactory: targetJobFactory, + BuildJobFactory: buildJobFactory, + RunnerJobFactory: runnerJobFactory, + }), nil +} + +func getRemoteProviderManager(params RemoteRunnerParams, logger *log.Logger) providermanager.IProviderManager { + headscaleUrl := util.GetFrpcHeadscaleUrl(params.ServerConfig.Frps.Protocol, params.ServerConfig.Id, params.ServerConfig.Frps.Domain) + binaryUrl, _ := url.JoinPath(params.RunnerConfig.ServerApiUrl, "binary", "script") + + return providermanager.GetProviderManager(&providermanager.ProviderManagerConfig{ + WorkspaceLogsDir: filepath.Join(params.ConfigDir, "workspaces", "logs"), + TargetLogsDir: filepath.Join(params.ConfigDir, "targets", "logs"), + ApiUrl: util.GetFrpcApiUrl(params.ServerConfig.Frps.Protocol, params.ServerConfig.Id, params.ServerConfig.Frps.Domain), + ApiKey: ¶ms.RunnerConfig.ServerApiKey, + RunnerId: params.RunnerConfig.Id, + RunnerName: params.RunnerConfig.Name, + Logger: logger, + DaytonaDownloadUrl: binaryUrl, + ServerUrl: headscaleUrl, + BaseDir: params.RunnerConfig.ProvidersDir, + CreateProviderNetworkKey: func(ctx context.Context, providerName string) (string, error) { + key, _, err := params.ApiClient.ServerAPI.CreateNetworkKey(ctx).Execute() + if err != nil { + return "", err + } + + return key.Key, nil + }, + ServerPort: uint32(params.ServerConfig.HeadscalePort), + ApiPort: uint32(params.ServerConfig.ApiPort), + GetTargetConfigMap: func(ctx context.Context) (map[string]*models.TargetConfig, error) { + list, _, err := params.ApiClient.TargetConfigAPI.ListTargetConfigs(ctx).Execute() + if err != nil { + return nil, err + } + + targetConfigs := make(map[string]*models.TargetConfig) + for _, targetConfig := range list { + tc, err := conversion.Convert[apiclient.TargetConfig, models.TargetConfig](&targetConfig) + if err != nil { + return nil, err + } + if tc == nil { + continue + } + + if tc.ProviderInfo.RunnerId != params.RunnerConfig.Id { + continue + } + + targetConfigs[targetConfig.Name] = tc + } + + return targetConfigs, nil + }, + CreateTargetConfig: func(ctx context.Context, name, options string, providerInfo models.ProviderInfo) error { + providerInfoDto, err := conversion.Convert[models.ProviderInfo, apiclient.ProviderInfo](&providerInfo) + if err != nil { + return err + } + if providerInfoDto == nil { + return errors.New("invalid provider info") + } + + _, _, err = params.ApiClient.TargetConfigAPI.CreateTargetConfig(ctx).TargetConfig(apiclient.CreateTargetConfigDTO{ + Name: fmt.Sprintf("%s-runner-%s", name, params.RunnerConfig.Id), + Options: options, + ProviderInfo: *providerInfoDto, + }).Execute() + return err + }, + }) +} + +func getRemoteWorkspaceJobFactory(params RemoteJobFactoryParams) (workspace.IWorkspaceJobFactory, error) { + logsDir := filepath.Join(params.ConfigDir, "workspaces", "logs") + loggerFactory := logs.NewLoggerFactory(logs.LoggerFactoryConfig{ + LogsDir: logsDir, + ApiUrl: ¶ms.RunnerConfig.ServerApiUrl, + ApiKey: ¶ms.RunnerConfig.ServerApiKey, + ApiBasePath: &logs.ApiBasePathWorkspace, + }) + + return workspace.NewWorkspaceJobFactory(workspace.WorkspaceJobFactoryConfig{ + FindWorkspace: func(ctx context.Context, workspaceId string) (*models.Workspace, error) { + workspaceDto, _, err := params.ApiClient.WorkspaceAPI.FindWorkspace(ctx, workspaceId).Execute() + if err != nil { + return nil, err + } + return conversion.Convert[apiclient.WorkspaceDTO, models.Workspace](workspaceDto) + }, + FindTarget: func(ctx context.Context, targetId string) (*models.Target, error) { + targetDto, _, err := params.ApiClient.TargetAPI.FindTarget(ctx, targetId).ShowOptions(true).Execute() + if err != nil { + return nil, err + } + return conversion.Convert[apiclient.TargetDTO, models.Target](targetDto) + }, + UpdateWorkspaceProviderMetadata: func(ctx context.Context, workspaceId, metadata string) error { + _, err := params.ApiClient.WorkspaceAPI.UpdateWorkspaceProviderMetadata(ctx, workspaceId).Metadata(apiclient.UpdateWorkspaceProviderMetadataDTO{ + Metadata: metadata, + }).Execute() + return err + }, + FindGitProviderConfig: func(ctx context.Context, id string) (*models.GitProviderConfig, error) { + gp, _, err := params.ApiClient.GitProviderAPI.FindGitProvider(ctx, id).Execute() + if err != nil { + return nil, err + } + + return conversion.Convert[apiclient.GitProvider, models.GitProviderConfig](gp) + }, + GetWorkspaceEnvironmentVariables: func(ctx context.Context, w *models.Workspace) (map[string]string, error) { + envVars, _, err := params.ApiClient.EnvVarAPI.ListEnvironmentVariables(ctx).Execute() + if err != nil { + return nil, err + } + + envVarsMap := make(map[string]string) + for _, envVar := range envVars { + envVarsMap[envVar.Key] = envVar.Value + } + + return util.MergeEnvVars(envVarsMap, w.EnvVars), nil + }, + TrackTelemetryEvent: func(event telemetry.Event, clientId string) error { + return params.TelemetryService.Track(event, clientId) + }, + LoggerFactory: loggerFactory, + ProviderManager: params.ProviderManager, + BuilderImage: params.ServerConfig.BuilderImage, + }), nil +} + +func getRemoteTargetJobFactory(params RemoteJobFactoryParams) (target.ITargetJobFactory, error) { + loggerFactory := logs.NewLoggerFactory(logs.LoggerFactoryConfig{ + LogsDir: filepath.Join(params.ConfigDir, "targets", "logs"), + ApiUrl: ¶ms.RunnerConfig.ServerApiUrl, + ApiKey: ¶ms.RunnerConfig.ServerApiKey, + ApiBasePath: &logs.ApiBasePathTarget, + }) + + return target.NewTargetJobFactory(target.TargetJobFactoryConfig{ + FindTarget: func(ctx context.Context, targetId string) (*models.Target, error) { + targetDto, _, err := params.ApiClient.TargetAPI.FindTarget(ctx, targetId).ShowOptions(true).Execute() + if err != nil { + return nil, err + } + + return conversion.Convert[apiclient.TargetDTO, models.Target](targetDto) + }, + HandleSuccessfulCreation: func(ctx context.Context, targetId string) error { + _, err := params.ApiClient.TargetAPI.HandleSuccessfulCreation(ctx, targetId).Execute() + return err + }, + UpdateTargetProviderMetadata: func(ctx context.Context, targetId, metadata string) error { + _, err := params.ApiClient.TargetAPI.UpdateTargetProviderMetadata(ctx, targetId).Metadata(apiclient.UpdateTargetProviderMetadataDTO{ + Metadata: metadata, + }).Execute() + return err + }, + TrackTelemetryEvent: func(event telemetry.Event, clientId string) error { + return params.TelemetryService.Track(event, clientId) + }, + LoggerFactory: loggerFactory, + ProviderManager: params.ProviderManager, + }), nil +} + +func getRemoteBuildJobFactory(params RemoteJobFactoryParams) (jobs_build.IBuildJobFactory, error) { + loggerFactory := logs.NewLoggerFactory(logs.LoggerFactoryConfig{ + LogsDir: filepath.Join(params.ConfigDir, "builds", "logs"), + ApiUrl: ¶ms.RunnerConfig.ServerApiUrl, + ApiKey: ¶ms.RunnerConfig.ServerApiKey, + ApiBasePath: &logs.ApiBasePathBuild, + }) + + cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) + if err != nil { + return nil, err + } + + dockerClient := docker.NewDockerClient(docker.DockerClientConfig{ + ApiClient: cli, + }) + + var buildImageNamespace string + + if params.ServerConfig.BuildImageNamespace != nil { + buildImageNamespace = *params.ServerConfig.BuildImageNamespace + if buildImageNamespace != "" { + buildImageNamespace = fmt.Sprintf("/%s", buildImageNamespace) + buildImageNamespace = strings.TrimSuffix(buildImageNamespace, "/") + } + } + + var builderRegistry *models.ContainerRegistry + + envVars, _, err := params.ApiClient.EnvVarAPI.ListEnvironmentVariables(context.Background()).Execute() + if err != nil { + builderRegistry = &models.ContainerRegistry{ + Server: params.ServerConfig.BuilderRegistryServer, + } + } + + envVarsMap := make(services.EnvironmentVariables) + for _, envVar := range envVars { + envVarsMap[envVar.Key] = envVar.Value + } + + if len(envVarsMap) > 0 { + builderRegistry = envVarsMap.FindContainerRegistry(params.ServerConfig.BuilderRegistryServer) + } + + if builderRegistry == nil { + builderRegistry = &models.ContainerRegistry{ + Server: util.GetFrpcRegistryDomain(params.ServerConfig.Id, params.ServerConfig.Frps.Domain), + } + } + + _, containerRegistries := common.ExtractContainerRegistryFromEnvVars(envVarsMap) + + return jobs_build.NewBuildJobFactory(jobs_build.BuildJobFactoryConfig{ + FindBuild: func(ctx context.Context, buildId string) (*services.BuildDTO, error) { + build, _, err := params.ApiClient.BuildAPI.FindBuild(ctx, buildId).Execute() + if err != nil { + return nil, err + } + + return conversion.Convert[apiclient.BuildDTO, services.BuildDTO](build) + }, + ListSuccessfulBuilds: func(ctx context.Context, repoUrl string) ([]*models.Build, error) { + apiclientBuildDtos, _, err := params.ApiClient.BuildAPI.ListSuccessfulBuilds(ctx, url.QueryEscape(repoUrl)).Execute() + if err != nil { + return nil, err + } + + var builds []*models.Build + for _, apiclientBuildDto := range apiclientBuildDtos { + buildDto, err := conversion.Convert[apiclient.BuildDTO, services.BuildDTO](&apiclientBuildDto) + if err != nil { + return nil, err + } + if buildDto == nil { + continue + } + builds = append(builds, &buildDto.Build) + } + return builds, nil + }, + ListConfigsForUrl: func(ctx context.Context, repoUrl string) ([]*models.GitProviderConfig, error) { + gitProviders, _, err := params.ApiClient.GitProviderAPI.ListGitProvidersForUrl(ctx, url.QueryEscape(repoUrl)).Execute() + if err != nil { + return nil, err + } + + var gitProviderConfigs []*models.GitProviderConfig + for _, gitProvider := range gitProviders { + gitProviderConfigDto, err := conversion.Convert[apiclient.GitProvider, models.GitProviderConfig](&gitProvider) + if err != nil { + return nil, err + } + if gitProviderConfigDto == nil { + continue + } + gitProviderConfigs = append(gitProviderConfigs, gitProviderConfigDto) + } + + return gitProviderConfigs, nil + }, + CheckImageExists: func(ctx context.Context, image string) bool { + _, _, err = cli.ImageInspectWithRaw(ctx, image) + return err == nil + }, + DeleteImage: func(ctx context.Context, image string, force bool) error { + return dockerClient.DeleteImage(image, force, nil) + }, + TrackTelemetryEvent: func(event telemetry.Event, clientId string) error { + return params.TelemetryService.Track(event, clientId) + }, + LoggerFactory: loggerFactory, + BuilderFactory: build.NewBuilderFactory(build.BuilderFactoryConfig{ + Image: params.ServerConfig.BuilderImage, + ContainerRegistries: containerRegistries, + BuildImageContainerRegistry: builderRegistry, + BuildImageNamespace: buildImageNamespace, + LoggerFactory: loggerFactory, + DefaultWorkspaceImage: params.ServerConfig.DefaultWorkspaceImage, + DefaultWorkspaceUser: params.ServerConfig.DefaultWorkspaceUser, + }), + BasePath: filepath.Join(params.ConfigDir, "builds"), + }), nil +} diff --git a/pkg/cmd/bootstrap/get_server_instance.go b/pkg/cmd/bootstrap/get_server_instance.go new file mode 100644 index 0000000000..39dc7b289c --- /dev/null +++ b/pkg/cmd/bootstrap/get_server_instance.go @@ -0,0 +1,518 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package bootstrap + +import ( + "context" + "errors" + "fmt" + "os" + "path/filepath" + + "github.com/daytonaio/daytona/cmd/daytona/config" + apikey_util "github.com/daytonaio/daytona/internal/apikeys" + "github.com/daytonaio/daytona/internal/constants" + "github.com/daytonaio/daytona/internal/util" + "github.com/daytonaio/daytona/pkg/db" + "github.com/daytonaio/daytona/pkg/gitprovider" + "github.com/daytonaio/daytona/pkg/logs" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/server" + "github.com/daytonaio/daytona/pkg/server/apikeys" + "github.com/daytonaio/daytona/pkg/server/builds" + "github.com/daytonaio/daytona/pkg/server/env" + "github.com/daytonaio/daytona/pkg/server/gitproviders" + "github.com/daytonaio/daytona/pkg/server/headscale" + "github.com/daytonaio/daytona/pkg/server/jobs" + "github.com/daytonaio/daytona/pkg/server/registry" + "github.com/daytonaio/daytona/pkg/server/runners" + "github.com/daytonaio/daytona/pkg/server/targetconfigs" + "github.com/daytonaio/daytona/pkg/server/targets" + "github.com/daytonaio/daytona/pkg/server/workspaces" + "github.com/daytonaio/daytona/pkg/server/workspacetemplates" + "github.com/daytonaio/daytona/pkg/services" + "github.com/daytonaio/daytona/pkg/stores" + "github.com/daytonaio/daytona/pkg/telemetry" + + log "github.com/sirupsen/logrus" +) + +func GetInstance(c *server.Config, configDir string, version string, telemetryService telemetry.TelemetryService) (*server.Server, error) { + dbPath, err := getDbPath() + if err != nil { + return nil, err + } + + dbConnection := db.GetSQLiteConnection(dbPath) + + store := db.NewStore(dbConnection) + + apiKeyStore, err := db.NewApiKeyStore(store) + if err != nil { + return nil, err + } + buildStore, err := db.NewBuildStore(store) + if err != nil { + return nil, err + } + workspaceTemplateStore, err := db.NewWorkspaceTemplateStore(store) + if err != nil { + return nil, err + } + gitProviderConfigStore, err := db.NewGitProviderConfigStore(store) + if err != nil { + return nil, err + } + targetConfigStore, err := db.NewTargetConfigStore(store) + if err != nil { + return nil, err + } + targetStore, err := db.NewTargetStore(store) + if err != nil { + return nil, err + } + targetMetadataStore, err := db.NewTargetMetadataStore(store) + if err != nil { + return nil, err + } + envVarStore, err := db.NewEnvironmentVariableStore(store) + if err != nil { + return nil, err + } + workspaceStore, err := db.NewWorkspaceStore(store) + if err != nil { + return nil, err + } + workspaceMetadataStore, err := db.NewWorkspaceMetadataStore(store) + if err != nil { + return nil, err + } + jobStore, err := db.NewJobStore(store) + if err != nil { + return nil, err + } + runnerStore, err := db.NewRunnerStore(store) + if err != nil { + return nil, err + } + runnerMetadataStore, err := db.NewRunnerMetadataStore(store) + if err != nil { + return nil, err + } + + headscaleServer := headscale.NewHeadscaleServer(&headscale.HeadscaleServerConfig{ + ServerId: c.Id, + FrpsDomain: c.Frps.Domain, + FrpsProtocol: c.Frps.Protocol, + HeadscalePort: c.HeadscalePort, + ConfigDir: filepath.Join(configDir, "headscale"), + Frps: c.Frps, + }) + err = headscaleServer.Init() + if err != nil { + return nil, err + } + + gitProviderService := gitproviders.NewGitProviderService(gitproviders.GitProviderServiceConfig{ + ConfigStore: gitProviderConfigStore, + DetachWorkspaceTemplates: func(ctx context.Context, gitProviderConfigId string) error { + workspaceTemplates, err := workspaceTemplateStore.List(ctx, &stores.WorkspaceTemplateFilter{ + GitProviderConfigId: &gitProviderConfigId, + }) + + if err != nil { + return err + } + + for _, workspaceTemplate := range workspaceTemplates { + workspaceTemplate.GitProviderConfigId = nil + err = workspaceTemplateStore.Save(ctx, workspaceTemplate) + if err != nil { + return err + } + } + + return nil + }, + TrackTelemetryEvent: func(event telemetry.Event, clientId string) error { + return telemetryService.Track(event, clientId) + }, + }) + + jobService := jobs.NewJobService(jobs.JobServiceConfig{ + JobStore: jobStore, + TrackTelemetryEvent: func(event telemetry.Event, clientId string) error { + return telemetryService.Track(event, clientId) + }, + UpdateWorkspaceLastJob: func(ctx context.Context, workspaceId string, jobId string) error { + workspaceService := server.GetInstance(nil).WorkspaceService + + return workspaceService.UpdateLastJob(ctx, workspaceId, jobId) + }, + UpdateTargetLastJob: func(ctx context.Context, targetId string, jobId string) error { + targetService := server.GetInstance(nil).TargetService + + return targetService.UpdateLastJob(ctx, targetId, jobId) + }, + UpdateBuildLastJob: func(ctx context.Context, buildId string, jobId string) error { + buildService := server.GetInstance(nil).BuildService + + return buildService.UpdateLastJob(ctx, buildId, jobId) + }, + }) + + buildService := builds.NewBuildService(builds.BuildServiceConfig{ + BuildStore: buildStore, + FindWorkspaceTemplate: func(ctx context.Context, name string) (*models.WorkspaceTemplate, error) { + return workspaceTemplateStore.Find(ctx, &stores.WorkspaceTemplateFilter{ + Name: &name, + }) + }, + GetRepositoryContext: func(ctx context.Context, url, branch string) (*gitprovider.GitRepository, error) { + gitProvider, _, err := gitProviderService.GetGitProviderForUrl(ctx, url) + if err != nil { + return nil, err + } + + repo, err := gitProvider.GetRepositoryContext(gitprovider.GetRepositoryContext{ + Url: url, + }) + + return repo, err + }, + CreateJob: func(ctx context.Context, buildId string, action models.JobAction) error { + return jobService.Create(ctx, &models.Job{ + ResourceId: buildId, + ResourceType: models.ResourceTypeBuild, + Action: action, + State: models.JobStatePending, + }) + }, + LoggerFactory: logs.NewLoggerFactory(logs.LoggerFactoryConfig{LogsDir: server.GetBuildLogsDir(configDir)}), + TrackTelemetryEvent: func(event telemetry.Event, clientId string) error { + return telemetryService.Track(event, clientId) + }, + }) + + prebuildWebhookEndpoint := fmt.Sprintf("%s%s", util.GetFrpcApiUrl(c.Frps.Protocol, c.Id, c.Frps.Domain), constants.WEBHOOK_EVENT_ROUTE) + + workspaceTemplateService := workspacetemplates.NewWorkspaceTemplateService(workspacetemplates.WorkspaceTemplateServiceConfig{ + PrebuildWebhookEndpoint: prebuildWebhookEndpoint, + ConfigStore: workspaceTemplateStore, + FindNewestBuild: func(ctx context.Context, prebuildId string) (*services.BuildDTO, error) { + return buildService.Find(ctx, &services.BuildFilter{ + StoreFilter: stores.BuildFilter{ + PrebuildIds: &[]string{prebuildId}, + GetNewest: util.Pointer(true), + }, + }) + }, + ListSuccessfulBuilds: func(ctx context.Context) ([]*services.BuildDTO, error) { + return buildService.List(ctx, &services.BuildFilter{ + StateNames: &[]models.ResourceStateName{models.ResourceStateNameRunSuccessful}, + }) + }, + CreateBuild: func(ctx context.Context, workspaceTemplate *models.WorkspaceTemplate, repo *gitprovider.GitRepository, prebuildId string) error { + createBuildDto := services.CreateBuildDTO{ + WorkspaceTemplateName: workspaceTemplate.Name, + Branch: repo.Branch, + PrebuildId: &prebuildId, + EnvVars: workspaceTemplate.EnvVars, + } + + _, err := buildService.Create(ctx, createBuildDto) + return err + }, + DeleteBuilds: func(ctx context.Context, id, prebuildId *string, force bool) []error { + var prebuildIds *[]string + if prebuildId != nil { + prebuildIds = &[]string{*prebuildId} + } + + return buildService.Delete(ctx, &services.BuildFilter{ + StoreFilter: stores.BuildFilter{ + Id: id, + PrebuildIds: prebuildIds, + }, + }, force) + }, + GetRepositoryContext: func(ctx context.Context, url string) (*gitprovider.GitRepository, string, error) { + gitProvider, gitProviderId, err := gitProviderService.GetGitProviderForUrl(ctx, url) + if err != nil { + return nil, "", err + } + + repo, err := gitProvider.GetRepositoryContext(gitprovider.GetRepositoryContext{ + Url: url, + }) + + return repo, gitProviderId, err + }, + FindPrebuildWebhook: func(ctx context.Context, gitProviderId string, repo *gitprovider.GitRepository, endpointUrl string) (*string, error) { + return gitProviderService.GetPrebuildWebhook(ctx, gitProviderId, repo, endpointUrl) + }, + UnregisterPrebuildWebhook: func(ctx context.Context, gitProviderId string, repo *gitprovider.GitRepository, id string) error { + return gitProviderService.UnregisterPrebuildWebhook(ctx, gitProviderId, repo, id) + }, + RegisterPrebuildWebhook: func(ctx context.Context, gitProviderId string, repo *gitprovider.GitRepository, endpointUrl string) (string, error) { + return gitProviderService.RegisterPrebuildWebhook(ctx, gitProviderId, repo, endpointUrl) + }, + GetCommitsRange: func(ctx context.Context, repo *gitprovider.GitRepository, initialSha, currentSha string) (int, error) { + gitProvider, _, err := gitProviderService.GetGitProviderForUrl(ctx, repo.Url) + if err != nil { + return 0, err + } + + return gitProvider.GetCommitsRange(repo, initialSha, currentSha) + }, + TrackTelemetryEvent: func(event telemetry.Event, clientId string) error { + return telemetryService.Track(event, clientId) + }, + }) + + err = workspaceTemplateService.StartRetentionPoller(context.Background()) + if err != nil { + return nil, err + } + + var localContainerRegistry server.ILocalContainerRegistry + + if c.BuilderRegistryServer != "local" { + envVarService := server.GetInstance(nil).EnvironmentVariableService + envVars, err := envVarService.Map(context.Background()) + if err != nil || envVars.FindContainerRegistry(c.BuilderRegistryServer) == nil { + log.Errorf("Failed to find container registry credentials for builder registry server %s\n", c.BuilderRegistryServer) + log.Errorf("Defaulting to local container registry. To use %s as the builder registry, add credentials for the registry server by adding them as environment variables using `daytona env set` and restart the server\n", c.BuilderRegistryServer) + c.BuilderRegistryServer = "local" + } + } + + if c.BuilderRegistryServer == "local" { + localContainerRegistry = registry.NewLocalContainerRegistry(®istry.LocalContainerRegistryConfig{ + DataPath: filepath.Join(configDir, "registry"), + Port: c.LocalBuilderRegistryPort, + Image: c.LocalBuilderRegistryImage, + Logger: log.StandardLogger().Writer(), + Frps: c.Frps, + ServerId: c.Id, + }) + c.BuilderRegistryServer = util.GetFrpcRegistryDomain(c.Id, c.Frps.Domain) + } + + targetConfigService := targetconfigs.NewTargetConfigService(targetconfigs.TargetConfigServiceConfig{ + TargetConfigStore: targetConfigStore, + TrackTelemetryEvent: func(event telemetry.Event, clientId string) error { + return telemetryService.Track(event, clientId) + }, + }) + + apiKeyService := apikeys.NewApiKeyService(apikeys.ApiKeyServiceConfig{ + ApiKeyStore: apiKeyStore, + GenerateRandomKey: func(name string) string { + return apikey_util.GenerateRandomKey() + }, + GetKeyHash: func(key string) string { + return apikey_util.HashKey(key) + }, + TrackTelemetryEvent: func(event telemetry.Event, clientId string) error { + return telemetryService.Track(event, clientId) + }, + }) + + headscaleUrl := util.GetFrpcHeadscaleUrl(c.Frps.Protocol, c.Id, c.Frps.Domain) + + targetService := targets.NewTargetService(targets.TargetServiceConfig{ + TargetStore: targetStore, + TargetMetadataStore: targetMetadataStore, + FindTargetConfig: func(ctx context.Context, name string) (*models.TargetConfig, error) { + return targetConfigService.Find(ctx, name) + }, + CreateApiKey: func(ctx context.Context, name string) (string, error) { + return apiKeyService.Create(ctx, models.ApiKeyTypeTarget, name) + }, + DeleteApiKey: func(ctx context.Context, name string) error { + return apiKeyService.Delete(ctx, name) + }, + CreateJob: func(ctx context.Context, targetId string, runnerId string, action models.JobAction) error { + return jobService.Create(ctx, &models.Job{ + ResourceId: targetId, + RunnerId: &runnerId, + ResourceType: models.ResourceTypeTarget, + Action: action, + State: models.JobStatePending, + }) + }, + TrackTelemetryEvent: func(event telemetry.Event, clientId string) error { + return telemetryService.Track(event, clientId) + }, + ServerApiUrl: util.GetFrpcApiUrl(c.Frps.Protocol, c.Id, c.Frps.Domain), + ServerVersion: version, + ServerUrl: headscaleUrl, + LoggerFactory: logs.NewLoggerFactory(logs.LoggerFactoryConfig{LogsDir: server.GetTargetLogsDir(configDir)}), + }) + + workspaceService := workspaces.NewWorkspaceService(workspaces.WorkspaceServiceConfig{ + WorkspaceStore: workspaceStore, + WorkspaceMetadataStore: workspaceMetadataStore, + FindTarget: func(ctx context.Context, targetId string) (*models.Target, error) { + t, err := targetService.Find(ctx, &stores.TargetFilter{IdOrName: &targetId}, services.TargetRetrievalParams{}) + if err != nil { + return nil, err + } + return &t.Target, nil + }, + FindContainerRegistry: func(ctx context.Context, image string, envVars map[string]string) *models.ContainerRegistry { + return services.EnvironmentVariables(envVars).FindContainerRegistryByImageName(image) + }, + FindCachedBuild: func(ctx context.Context, w *models.Workspace) (*models.CachedBuild, error) { + validStates := []models.ResourceStateName{ + models.ResourceStateNameRunSuccessful, + } + + build, err := buildService.Find(ctx, &services.BuildFilter{ + StateNames: &validStates, + StoreFilter: stores.BuildFilter{ + RepositoryUrl: &w.Repository.Url, + Branch: &w.Repository.Branch, + EnvVars: &w.EnvVars, + BuildConfig: w.BuildConfig, + GetNewest: util.Pointer(true), + }, + }) + if err != nil { + return nil, err + } + + if build.Image == nil || build.User == nil { + return nil, errors.New("cached build is missing image or user") + } + + return &models.CachedBuild{ + User: *build.User, + Image: *build.Image, + }, nil + }, + CreateApiKey: func(ctx context.Context, name string) (string, error) { + return apiKeyService.Create(ctx, models.ApiKeyTypeWorkspace, name) + }, + DeleteApiKey: func(ctx context.Context, name string) error { + return apiKeyService.Delete(ctx, name) + }, + ListGitProviderConfigs: func(ctx context.Context, repoUrl string) ([]*models.GitProviderConfig, error) { + return gitProviderService.ListConfigsForUrl(ctx, repoUrl) + }, + FindGitProviderConfig: func(ctx context.Context, id string) (*models.GitProviderConfig, error) { + return gitProviderService.FindConfig(ctx, id) + }, + GetLastCommitSha: func(ctx context.Context, repo *gitprovider.GitRepository) (string, error) { + return gitProviderService.GetLastCommitSha(ctx, repo) + }, + CreateJob: func(ctx context.Context, workspaceId string, runnerId string, action models.JobAction) error { + return jobService.Create(ctx, &models.Job{ + ResourceId: workspaceId, + RunnerId: &runnerId, + ResourceType: models.ResourceTypeWorkspace, + Action: action, + State: models.JobStatePending, + }) + }, + TrackTelemetryEvent: func(event telemetry.Event, clientId string) error { + return telemetryService.Track(event, clientId) + }, + ServerApiUrl: util.GetFrpcApiUrl(c.Frps.Protocol, c.Id, c.Frps.Domain), + ServerVersion: version, + ServerUrl: headscaleUrl, + DefaultWorkspaceImage: c.DefaultWorkspaceImage, + DefaultWorkspaceUser: c.DefaultWorkspaceUser, + LoggerFactory: logs.NewLoggerFactory(logs.LoggerFactoryConfig{LogsDir: server.GetWorkspaceLogsDir(configDir)}), + }) + + envVarService := env.NewEnvironmentVariableService(env.EnvironmentVariableServiceConfig{ + EnvironmentVariableStore: envVarStore, + }) + + runnerService := runners.NewRunnerService(runners.RunnerServiceConfig{ + RunnerStore: runnerStore, + RunnerMetadataStore: runnerMetadataStore, + LoggerFactory: logs.NewLoggerFactory(logs.LoggerFactoryConfig{LogsDir: server.GetRunnerLogsDir(configDir)}), + CreateJob: func(ctx context.Context, runnerId string, action models.JobAction, metadata string) error { + return jobService.Create(ctx, &models.Job{ + ResourceId: runnerId, + RunnerId: &runnerId, + ResourceType: models.ResourceTypeRunner, + Action: action, + State: models.JobStatePending, + Metadata: &metadata, + }) + }, + ListJobsForRunner: func(ctx context.Context, runnerId string) ([]*models.Job, error) { + return jobService.List(ctx, &stores.JobFilter{ + RunnerIdOrIsNil: &runnerId, + States: &[]models.JobState{models.JobStatePending}, + }) + }, + UpdateJobState: func(ctx context.Context, jobId string, updateJobStateDto services.UpdateJobStateDTO) error { + return jobService.UpdateState(ctx, jobId, updateJobStateDto) + }, + CreateApiKey: func(ctx context.Context, name string) (string, error) { + return apiKeyService.Create(ctx, models.ApiKeyTypeRunner, name) + }, + DeleteApiKey: apiKeyService.Delete, + UnsetDefaultTarget: func(ctx context.Context, runnerId string) error { + targets, err := targetService.List(ctx, nil, services.TargetRetrievalParams{}) + if err != nil { + return err + } + + for _, t := range targets { + if t.TargetConfig.ProviderInfo.RunnerId == runnerId && t.IsDefault { + t.IsDefault = false + err = targetService.Save(ctx, &t.Target) + if err != nil { + return err + } + break + } + } + return nil + }, + TrackTelemetryEvent: func(event telemetry.Event, clientId string) error { + return telemetryService.Track(event, clientId) + }, + }) + + s := server.GetInstance(&server.ServerInstanceConfig{ + Config: *c, + Version: version, + TailscaleServer: headscaleServer, + TargetConfigService: targetConfigService, + BuildService: buildService, + WorkspaceTemplateService: workspaceTemplateService, + WorkspaceService: workspaceService, + LocalContainerRegistry: localContainerRegistry, + ApiKeyService: apiKeyService, + TargetService: targetService, + GitProviderService: gitProviderService, + EnvironmentVariableService: envVarService, + JobService: jobService, + RunnerService: runnerService, + TelemetryService: telemetryService, + }) + + return s, s.Initialize() +} + +func getDbPath() (string, error) { + configDir, err := config.GetConfigDir() + if err != nil { + return "", err + } + + err = os.MkdirAll(configDir, 0755) + if err != nil { + return "", err + } + + return filepath.Join(configDir, "db"), nil +} diff --git a/pkg/cmd/build/build.go b/pkg/cmd/build/build.go index 877da28a89..03e9746348 100644 --- a/pkg/cmd/build/build.go +++ b/pkg/cmd/build/build.go @@ -10,15 +10,16 @@ import ( var BuildCmd = &cobra.Command{ Use: "build", - Aliases: []string{"builds"}, Short: "Manage builds", - GroupID: util.WORKSPACE_GROUP, + Args: cobra.NoArgs, + GroupID: util.TARGET_GROUP, + Aliases: []string{"builds"}, } func init() { - BuildCmd.AddCommand(buildListCmd) - BuildCmd.AddCommand(buildInfoCmd) - BuildCmd.AddCommand(buildRunCmd) - BuildCmd.AddCommand(buildDeleteCmd) - BuildCmd.AddCommand(buildLogsCmd) + BuildCmd.AddCommand(listCmd) + BuildCmd.AddCommand(infoCmd) + BuildCmd.AddCommand(runCmd) + BuildCmd.AddCommand(deleteCmd) + BuildCmd.AddCommand(logsCmd) } diff --git a/pkg/cmd/build/delete.go b/pkg/cmd/build/delete.go index e9400d1577..58c0fa1b1b 100644 --- a/pkg/cmd/build/delete.go +++ b/pkg/cmd/build/delete.go @@ -8,17 +8,18 @@ import ( "fmt" apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" + "github.com/daytonaio/daytona/pkg/cmd/common" "github.com/daytonaio/daytona/pkg/views" + "github.com/daytonaio/daytona/pkg/views/selection" views_util "github.com/daytonaio/daytona/pkg/views/util" - "github.com/daytonaio/daytona/pkg/views/workspace/selection" "github.com/spf13/cobra" ) -var buildDeleteCmd = &cobra.Command{ +var deleteCmd = &cobra.Command{ Use: "delete [BUILD]", Short: "Delete a build", - Aliases: []string{"remove", "rm"}, Args: cobra.RangeArgs(0, 1), + Aliases: common.GetAliases("delete"), RunE: func(cmd *cobra.Command, args []string) error { ctx := context.Background() var buildId string @@ -82,7 +83,7 @@ var forceFlag bool var prebuildIdFlag string func init() { - buildDeleteCmd.Flags().BoolVarP(&allFlag, "all", "a", false, "Delete ALL builds") - buildDeleteCmd.Flags().BoolVarP(&forceFlag, "force", "f", false, "Force delete build") - buildDeleteCmd.Flags().StringVar(&prebuildIdFlag, "prebuild-id", "", "Delete ALL builds from prebuild") + deleteCmd.Flags().BoolVarP(&allFlag, "all", "a", false, "Delete ALL builds") + deleteCmd.Flags().BoolVarP(&forceFlag, "force", "f", false, "Force delete build") + deleteCmd.Flags().StringVar(&prebuildIdFlag, "prebuild-id", "", "Delete ALL builds from prebuild") } diff --git a/pkg/cmd/build/info.go b/pkg/cmd/build/info.go index 7af105a0be..5cd3a0b137 100644 --- a/pkg/cmd/build/info.go +++ b/pkg/cmd/build/info.go @@ -9,21 +9,22 @@ import ( apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" "github.com/daytonaio/daytona/pkg/apiclient" + "github.com/daytonaio/daytona/pkg/cmd/common" "github.com/daytonaio/daytona/pkg/cmd/format" "github.com/daytonaio/daytona/pkg/views/build/info" + "github.com/daytonaio/daytona/pkg/views/selection" views_util "github.com/daytonaio/daytona/pkg/views/util" - "github.com/daytonaio/daytona/pkg/views/workspace/selection" "github.com/spf13/cobra" ) -var buildInfoCmd = &cobra.Command{ +var infoCmd = &cobra.Command{ Use: "info [BUILD]", Short: "Show build info", - Aliases: []string{"view", "inspect"}, Args: cobra.RangeArgs(0, 1), + Aliases: common.GetAliases("info"), RunE: func(cmd *cobra.Command, args []string) error { ctx := context.Background() - var build *apiclient.Build + var build *apiclient.BuildDTO apiClient, err := apiclient_util.GetApiClient(nil) if err != nil { @@ -60,7 +61,7 @@ var buildInfoCmd = &cobra.Command{ } } else { var res *http.Response - build, res, err = apiClient.BuildAPI.GetBuild(ctx, args[0]).Execute() + build, res, err = apiClient.BuildAPI.FindBuild(ctx, args[0]).Execute() if err != nil { return apiclient_util.HandleErrorResponse(res, err) } @@ -78,5 +79,5 @@ var buildInfoCmd = &cobra.Command{ } func init() { - format.RegisterFormatFlag(buildInfoCmd) + format.RegisterFormatFlag(infoCmd) } diff --git a/pkg/cmd/build/list.go b/pkg/cmd/build/list.go index e6491ce66d..1850dc22b4 100644 --- a/pkg/cmd/build/list.go +++ b/pkg/cmd/build/list.go @@ -7,16 +7,17 @@ import ( "context" apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" + "github.com/daytonaio/daytona/pkg/cmd/common" "github.com/daytonaio/daytona/pkg/cmd/format" view "github.com/daytonaio/daytona/pkg/views/build/list" "github.com/spf13/cobra" ) -var buildListCmd = &cobra.Command{ +var listCmd = &cobra.Command{ Use: "list", Short: "List all builds", - Aliases: []string{"ls"}, Args: cobra.NoArgs, + Aliases: common.GetAliases("ls"), RunE: func(cmd *cobra.Command, args []string) error { ctx := context.Background() @@ -47,5 +48,5 @@ var buildListCmd = &cobra.Command{ } func init() { - format.RegisterFormatFlag(buildListCmd) + format.RegisterFormatFlag(listCmd) } diff --git a/pkg/cmd/build/logs.go b/pkg/cmd/build/logs.go index 143b9162b8..dafe4c3828 100644 --- a/pkg/cmd/build/logs.go +++ b/pkg/cmd/build/logs.go @@ -9,16 +9,18 @@ import ( "github.com/daytonaio/daytona/cmd/daytona/config" apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" + "github.com/daytonaio/daytona/pkg/cmd/common" + cmd_common "github.com/daytonaio/daytona/pkg/cmd/common" + "github.com/daytonaio/daytona/pkg/views/selection" views_util "github.com/daytonaio/daytona/pkg/views/util" - "github.com/daytonaio/daytona/pkg/views/workspace/selection" "github.com/spf13/cobra" ) -var buildLogsCmd = &cobra.Command{ +var logsCmd = &cobra.Command{ Use: "logs", Short: "View logs for build", Args: cobra.RangeArgs(0, 1), - Aliases: []string{"log"}, + Aliases: common.GetAliases("logs"), RunE: func(cmd *cobra.Command, args []string) error { c, err := config.GetConfig() if err != nil { @@ -30,11 +32,6 @@ var buildLogsCmd = &cobra.Command{ return err } - query := "" - if followFlag { - query += "follow=true" - } - ctx := context.Background() var buildId string @@ -63,12 +60,17 @@ var buildLogsCmd = &cobra.Command{ buildId = args[0] } - _, _, err = apiClient.BuildAPI.GetBuild(ctx, buildId).Execute() + _, _, err = apiClient.BuildAPI.FindBuild(ctx, buildId).Execute() if err != nil { return apiclient_util.HandleErrorResponse(nil, err) } - apiclient_util.ReadBuildLogs(ctx, activeProfile, buildId, query) + cmd_common.ReadBuildLogs(ctx, cmd_common.ReadLogParams{ + Id: buildId, + ServerUrl: activeProfile.Api.Url, + ApiKey: activeProfile.Api.Key, + Follow: &followFlag, + }) // Make sure the terminal cursor is reset fmt.Print("\033[?25h") @@ -80,5 +82,5 @@ var buildLogsCmd = &cobra.Command{ var followFlag bool func init() { - buildLogsCmd.Flags().BoolVarP(&followFlag, "follow", "f", false, "Follow logs") + logsCmd.Flags().BoolVarP(&followFlag, "follow", "f", false, "Follow logs") } diff --git a/pkg/cmd/build/run.go b/pkg/cmd/build/run.go index d4422f1232..771b3aeb41 100644 --- a/pkg/cmd/build/run.go +++ b/pkg/cmd/build/run.go @@ -8,22 +8,23 @@ import ( "errors" "fmt" - "github.com/daytonaio/daytona/internal/util" apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" "github.com/daytonaio/daytona/pkg/apiclient" - workspace_util "github.com/daytonaio/daytona/pkg/cmd/workspace/util" + "github.com/daytonaio/daytona/pkg/cmd/common" + "github.com/daytonaio/daytona/pkg/cmd/workspace/create" "github.com/daytonaio/daytona/pkg/views" - "github.com/daytonaio/daytona/pkg/views/workspace/selection" + "github.com/daytonaio/daytona/pkg/views/selection" + views_util "github.com/daytonaio/daytona/pkg/views/util" "github.com/spf13/cobra" ) -var buildRunCmd = &cobra.Command{ +var runCmd = &cobra.Command{ Use: "run", - Short: "Run a build from a project config", - Aliases: []string{"create"}, + Short: "Run a build from a workspace template", Args: cobra.NoArgs, + Aliases: common.GetAliases("run"), RunE: func(cmd *cobra.Command, args []string) error { - var projectConfig *apiclient.ProjectConfig + var workspaceTemplate *apiclient.WorkspaceTemplate ctx := context.Background() apiClient, err := apiclient_util.GetApiClient(nil) @@ -31,21 +32,26 @@ var buildRunCmd = &cobra.Command{ return err } - projectConfigList, res, err := apiClient.ProjectConfigAPI.ListProjectConfigs(ctx).Execute() + workspaceTemplateList, res, err := apiClient.WorkspaceTemplateAPI.ListWorkspaceTemplates(ctx).Execute() if err != nil { return apiclient_util.HandleErrorResponse(res, err) } - projectConfig = selection.GetProjectConfigFromPrompt(projectConfigList, 0, false, false, "Build") - if projectConfig == nil { + if len(workspaceTemplateList) == 0 { + views_util.NotifyEmptyWorkspaceTemplateList(true) return nil } - if projectConfig.BuildConfig == nil { - return errors.New("The chosen project config does not have a build configuration") + workspaceTemplate = selection.GetWorkspaceTemplateFromPrompt(workspaceTemplateList, 0, false, false, "Build") + if workspaceTemplate == nil { + return nil + } + + if workspaceTemplate.BuildConfig == nil { + return errors.New("The chosen workspace template does not have a build configuration") } - chosenBranch, err := workspace_util.GetBranchFromProjectConfig(projectConfig, apiClient, 0) + chosenBranch, err := create.GetBranchFromWorkspaceTemplate(ctx, workspaceTemplate, apiClient, 0) if err != nil { return err } @@ -55,7 +61,7 @@ var buildRunCmd = &cobra.Command{ return nil } - buildId, err := CreateBuild(apiClient, projectConfig, chosenBranch.Name, nil) + buildId, err := CreateBuild(apiClient, workspaceTemplate, chosenBranch.Name, nil) if err != nil { return err } @@ -65,28 +71,18 @@ var buildRunCmd = &cobra.Command{ }, } -func CreateBuild(apiClient *apiclient.APIClient, projectConfig *apiclient.ProjectConfig, branch string, prebuildId *string) (string, error) { +func CreateBuild(apiClient *apiclient.APIClient, workspaceTemplate *apiclient.WorkspaceTemplate, branch string, prebuildId *string) (string, error) { ctx := context.Background() - profileData, res, err := apiClient.ProfileAPI.GetProfileData(ctx).Execute() - if err != nil { - return "", apiclient_util.HandleErrorResponse(res, err) - } - - if projectConfig.BuildConfig == nil { - return "", errors.New("the chosen project config does not have a build configuration") + if workspaceTemplate.BuildConfig == nil { + return "", errors.New("the chosen workspace template does not have a build configuration") } createBuildDto := apiclient.CreateBuildDTO{ - ProjectConfigName: projectConfig.Name, - Branch: branch, - PrebuildId: prebuildId, - } - - if profileData != nil { - createBuildDto.EnvVars = util.MergeEnvVars(profileData.EnvVars, projectConfig.EnvVars) - } else { - createBuildDto.EnvVars = util.MergeEnvVars(projectConfig.EnvVars) + WorkspaceTemplateName: workspaceTemplate.Name, + Branch: branch, + PrebuildId: prebuildId, + EnvVars: workspaceTemplate.EnvVars, } buildId, res, err := apiClient.BuildAPI.CreateBuild(ctx).CreateBuildDto(createBuildDto).Execute() diff --git a/pkg/cmd/cmd.go b/pkg/cmd/cmd.go index 3d79239d14..1efd518fa0 100644 --- a/pkg/cmd/cmd.go +++ b/pkg/cmd/cmd.go @@ -12,25 +12,26 @@ import ( "time" "github.com/daytonaio/daytona/cmd/daytona/config" - "github.com/daytonaio/daytona/internal" . "github.com/daytonaio/daytona/internal/util" . "github.com/daytonaio/daytona/pkg/cmd/apikey" . "github.com/daytonaio/daytona/pkg/cmd/autocomplete" . "github.com/daytonaio/daytona/pkg/cmd/build" - . "github.com/daytonaio/daytona/pkg/cmd/containerregistry" + cmd_common "github.com/daytonaio/daytona/pkg/cmd/common" + . "github.com/daytonaio/daytona/pkg/cmd/env" . "github.com/daytonaio/daytona/pkg/cmd/gitprovider" . "github.com/daytonaio/daytona/pkg/cmd/ports" . "github.com/daytonaio/daytona/pkg/cmd/prebuild" . "github.com/daytonaio/daytona/pkg/cmd/profile" - . "github.com/daytonaio/daytona/pkg/cmd/profiledata/env" - . "github.com/daytonaio/daytona/pkg/cmd/projectconfig" . "github.com/daytonaio/daytona/pkg/cmd/provider" + . "github.com/daytonaio/daytona/pkg/cmd/runner" . "github.com/daytonaio/daytona/pkg/cmd/server" . "github.com/daytonaio/daytona/pkg/cmd/target" + . "github.com/daytonaio/daytona/pkg/cmd/targetconfig" . "github.com/daytonaio/daytona/pkg/cmd/telemetry" . "github.com/daytonaio/daytona/pkg/cmd/workspace" + . "github.com/daytonaio/daytona/pkg/cmd/workspace/create" + . "github.com/daytonaio/daytona/pkg/cmd/workspacetemplate" "github.com/daytonaio/daytona/pkg/common" - "github.com/daytonaio/daytona/pkg/posthogservice" "github.com/daytonaio/daytona/pkg/telemetry" view "github.com/daytonaio/daytona/pkg/views/initial" log "github.com/sirupsen/logrus" @@ -49,25 +50,26 @@ var rootCmd = &cobra.Command{ } func Execute() error { - rootCmd.AddGroup(&cobra.Group{ID: WORKSPACE_GROUP, Title: "Workspaces & Projects"}) + rootCmd.AddGroup(&cobra.Group{ID: TARGET_GROUP, Title: "Targets & Workspaces"}) rootCmd.AddGroup(&cobra.Group{ID: SERVER_GROUP, Title: "Server"}) rootCmd.AddGroup(&cobra.Group{ID: PROFILE_GROUP, Title: "Profile"}) + rootCmd.AddGroup(&cobra.Group{ID: RUNNER_GROUP, Title: "Runner"}) rootCmd.AddCommand(CodeCmd) rootCmd.AddCommand(SshCmd) rootCmd.AddCommand(SshProxyCmd) rootCmd.AddCommand(CreateCmd) rootCmd.AddCommand(DeleteCmd) - rootCmd.AddCommand(ProjectConfigCmd) + rootCmd.AddCommand(WorkspaceTemplateCmd) rootCmd.AddCommand(ServeCmd) rootCmd.AddCommand(DaemonServeCmd) rootCmd.AddCommand(ServerCmd) rootCmd.AddCommand(ApiKeyCmd) - rootCmd.AddCommand(ContainerRegistryCmd) rootCmd.AddCommand(ProviderCmd) - rootCmd.AddCommand(TargetCmd) + rootCmd.AddCommand(TargetConfigCmd) rootCmd.AddCommand(configCmd) rootCmd.AddCommand(ideCmd) + rootCmd.AddCommand(RunnerCmd) rootCmd.AddCommand(ProfileCmd) rootCmd.AddCommand(ProfileUseCmd) rootCmd.AddCommand(whoamiCmd) @@ -76,6 +78,7 @@ func Execute() error { rootCmd.AddCommand(StartCmd) rootCmd.AddCommand(StopCmd) rootCmd.AddCommand(RestartCmd) + rootCmd.AddCommand(LogsCmd) rootCmd.AddCommand(InfoCmd) rootCmd.AddCommand(PrebuildCmd) rootCmd.AddCommand(BuildCmd) @@ -83,6 +86,7 @@ func Execute() error { rootCmd.AddCommand(EnvCmd) rootCmd.AddCommand(TelemetryCmd) rootCmd.AddCommand(updateCmd) + rootCmd.AddCommand(TargetCmd) SetupRootCommand(rootCmd) @@ -90,7 +94,7 @@ func Execute() error { clientId := config.GetClientId() telemetryEnabled := config.TelemetryEnabled() - telemetryService, cmd, flags, isCompletion, err := PreRun(rootCmd, os.Args[1:], telemetryEnabled, clientId, startTime) + cmd, flags, isCompletion, err := PreRun(rootCmd, os.Args[1:], telemetryEnabled, clientId, startTime) if err != nil { fmt.Printf("Error: %v\n\n", err) return cmd.Help() @@ -101,7 +105,7 @@ func Execute() error { endTime := time.Now() if !isCompletion { - PostRun(cmd, err, telemetryService, clientId, startTime, endTime, flags) + PostRun(cmd, err, clientId, startTime, endTime, flags) } return err @@ -153,7 +157,6 @@ func SetupRootCommand(cmd *cobra.Command) { cmd.AddCommand(ListCmd) cmd.AddCommand(generateDocsCmd) cmd.AddCommand(DocsCmd) - cmd.AddCommand(logsCmd) cmd.CompletionOptions.HiddenDefaultCmd = true cmd.PersistentFlags().BoolP("help", "", false, "help for daytona") @@ -188,10 +191,10 @@ func RunInitialScreenFlow(cmd *cobra.Command, args []string) error { return CreateCmd.RunE(cmd, []string{}) case "code": return CodeCmd.RunE(cmd, []string{}) - case "git-provider add": - return GitProviderAddCmd.RunE(cmd, []string{}) - case "target set": - return TargetSetCmd.RunE(cmd, []string{}) + case "git-provider create": + return GitProviderCreateCmd.RunE(cmd, []string{}) + case "target-config create": + return TargetConfigCreateCmd.RunE(cmd, []string{}) case "docs": return DocsCmd.RunE(cmd, []string{}) case "help": @@ -201,58 +204,27 @@ func RunInitialScreenFlow(cmd *cobra.Command, args []string) error { return nil } -func GetCmdTelemetryData(cmd *cobra.Command, flags []string) map[string]interface{} { - path := cmd.CommandPath() - - // Trim daytona from the path if a non-root command was invoked - // This prevents a `daytona` pileup in the telemetry data - if path != "daytona" { - path = strings.TrimPrefix(path, "daytona ") - } - - source := telemetry.CLI_SOURCE - if internal.WorkspaceMode() { - source = telemetry.CLI_PROJECT_SOURCE - } - - calledAs := cmd.CalledAs() - - data := telemetry.AdditionalData - data["command"] = path - data["called_as"] = calledAs - data["source"] = source - data["flags"] = flags - - return data -} - -func PreRun(rootCmd *cobra.Command, args []string, telemetryEnabled bool, clientId string, startTime time.Time) (telemetry.TelemetryService, *cobra.Command, []string, bool, error) { - var telemetryService telemetry.TelemetryService - - if telemetryEnabled { - telemetryService = posthogservice.NewTelemetryService(posthogservice.PosthogServiceConfig{ - ApiKey: internal.PosthogApiKey, - Endpoint: internal.PosthogEndpoint, - Version: internal.Version, - }) - } - +func PreRun(rootCmd *cobra.Command, args []string, telemetryEnabled bool, clientId string, startTime time.Time) (*cobra.Command, []string, bool, error) { cmd, flags, isCompletion, err := validateCommands(rootCmd, os.Args[1:]) if err != nil && !isCompletion { - if telemetryEnabled && !strings.HasSuffix(cmd.CommandPath(), "daemon-serve") { - props := GetCmdTelemetryData(cmd, flags) - err := telemetryService.TrackCliEvent(telemetry.CliEventInvalidCmd, clientId, props) + if !shouldIgnoreCommand(cmd.CommandPath()) { + event := telemetry.NewCliEvent(telemetry.CliEventCommandInvalid, cmd, flags, err, nil) + err := cmd_common.TrackTelemetryEvent(event, clientId) + if err != nil { + log.Trace(err) + } + err = cmd_common.CloseTelemetryService() if err != nil { log.Trace(err) } - telemetryService.Close() } - return telemetryService, cmd, flags, isCompletion, err + return cmd, flags, isCompletion, err } - if telemetryEnabled && !strings.HasSuffix(cmd.CommandPath(), "daemon-serve") && !isCompletion { - err := telemetryService.TrackCliEvent(telemetry.CliEventCmdStart, clientId, GetCmdTelemetryData(cmd, flags)) + if !shouldIgnoreCommand(cmd.CommandPath()) && !isCompletion { + event := telemetry.NewCliEvent(telemetry.CliEventCommandStarted, cmd, flags, nil, nil) + err := cmd_common.TrackTelemetryEvent(event, clientId) if err != nil { log.Trace(err) } @@ -264,36 +236,55 @@ func PreRun(rootCmd *cobra.Command, args []string, telemetryEnabled bool, client for range interruptChannel { endTime := time.Now() execTime := endTime.Sub(startTime) - props := GetCmdTelemetryData(cmd, flags) - props["exec time (µs)"] = execTime.Microseconds() - props["error"] = "interrupted" + extras := map[string]interface{}{"exec_time_µs": execTime.Microseconds()} + event := telemetry.NewCliEvent(telemetry.CliEventCommandInterrupted, cmd, flags, nil, extras) + err := cmd_common.TrackTelemetryEvent(event, clientId) + if err != nil { + log.Trace(err) + } - err := telemetryService.TrackCliEvent(telemetry.CliEventCmdEnd, clientId, props) + err = cmd_common.CloseTelemetryService() if err != nil { log.Trace(err) } - telemetryService.Close() os.Exit(0) } }() } - return telemetryService, cmd, flags, isCompletion, nil + return cmd, flags, isCompletion, nil } -func PostRun(cmd *cobra.Command, cmdErr error, telemetryService telemetry.TelemetryService, clientId string, startTime time.Time, endTime time.Time, flags []string) { - if telemetryService != nil && !strings.HasSuffix(cmd.CommandPath(), "daemon-serve") { +func PostRun(cmd *cobra.Command, cmdErr error, clientId string, startTime time.Time, endTime time.Time, flags []string) { + if !shouldIgnoreCommand(cmd.CommandPath()) { execTime := endTime.Sub(startTime) - props := GetCmdTelemetryData(cmd, flags) - props["exec time (µs)"] = execTime.Microseconds() + extras := map[string]interface{}{"exec_time_µs": execTime.Microseconds()} + eventName := telemetry.CliEventCommandCompleted if cmdErr != nil { - props["error"] = cmdErr.Error() + eventName = telemetry.CliEventCommandFailed } + event := telemetry.NewCliEvent(eventName, cmd, flags, cmdErr, extras) - err := telemetryService.TrackCliEvent(telemetry.CliEventCmdEnd, clientId, props) + err := cmd_common.TrackTelemetryEvent(event, clientId) + if err != nil { + log.Trace(err) + } + + err = cmd_common.CloseTelemetryService() if err != nil { log.Trace(err) } - telemetryService.Close() } } + +func shouldIgnoreCommand(commandPath string) bool { + ignoredPaths := []string{"daemon-serve", "ssh-proxy"} + + for _, ignoredPath := range ignoredPaths { + if strings.HasSuffix(commandPath, ignoredPath) { + return true + } + } + + return false +} diff --git a/pkg/cmd/common/aliases.go b/pkg/cmd/common/aliases.go new file mode 100644 index 0000000000..c6465bec65 --- /dev/null +++ b/pkg/cmd/common/aliases.go @@ -0,0 +1,26 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package common + +var commandAliases = map[string][]string{ + "create": {"add", "new"}, + "delete": {"remove", "rm"}, + "update": {"set"}, + "install": {"i"}, + "uninstall": {"u"}, + "info": {"view", "inspect"}, + "code": {"open"}, + "logs": {"log"}, + "forward": {"fwd"}, + "list": {"ls"}, + "set-default": {"sd"}, + "run": {"create"}, +} + +func GetAliases(cmd string) []string { + if aliases, exists := commandAliases[cmd]; exists { + return aliases + } + return nil +} diff --git a/pkg/cmd/workspace/util/workspace.go b/pkg/cmd/common/configuration_flags.go similarity index 51% rename from pkg/cmd/workspace/util/workspace.go rename to pkg/cmd/common/configuration_flags.go index a6092cc172..01d6dc4822 100644 --- a/pkg/cmd/workspace/util/workspace.go +++ b/pkg/cmd/common/configuration_flags.go @@ -1,18 +1,17 @@ // Copyright 2024 Daytona Platforms Inc. // SPDX-License-Identifier: Apache-2.0 -package util +package common import ( - "errors" "fmt" + "strings" - "github.com/daytonaio/daytona/pkg/apiclient" views_util "github.com/daytonaio/daytona/pkg/views/util" "github.com/spf13/cobra" ) -type ProjectConfigurationFlags struct { +type WorkspaceConfigurationFlags struct { Builder *views_util.BuildChoice CustomImage *string CustomImageUser *string @@ -21,16 +20,18 @@ type ProjectConfigurationFlags struct { EnvVars *[]string Manual *bool GitProviderConfig *string + Labels *[]string } -func AddProjectConfigurationFlags(cmd *cobra.Command, flags ProjectConfigurationFlags, multiProjectFlagException bool) { - cmd.Flags().StringVar(flags.CustomImage, "custom-image", "", "Create the project with the custom image passed as the flag value; Requires setting --custom-image-user flag as well") - cmd.Flags().StringVar(flags.CustomImageUser, "custom-image-user", "", "Create the project with the custom image user passed as the flag value; Requires setting --custom-image flag as well") +func AddWorkspaceConfigurationFlags(cmd *cobra.Command, flags WorkspaceConfigurationFlags, multiWorkspaceFlagException bool) { + cmd.Flags().StringVar(flags.CustomImage, "custom-image", "", "Create the workspace with the custom image passed as the flag value; Requires setting --custom-image-user flag as well") + cmd.Flags().StringVar(flags.CustomImageUser, "custom-image-user", "", "Create the workspace with the custom image user passed as the flag value; Requires setting --custom-image flag as well") cmd.Flags().StringVar(flags.DevcontainerPath, "devcontainer-path", "", "Automatically assign the devcontainer builder with the path passed as the flag value") cmd.Flags().Var(flags.Builder, "builder", fmt.Sprintf("Specify the builder (currently %s/%s/%s)", views_util.AUTOMATIC, views_util.DEVCONTAINER, views_util.NONE)) cmd.Flags().StringArrayVar(flags.EnvVars, "env", []string{}, "Specify environment variables (e.g. --env 'KEY1=VALUE1' --env 'KEY2=VALUE2' ...')") cmd.Flags().BoolVar(flags.Manual, "manual", false, "Manually enter the Git repository") cmd.Flags().StringVar(flags.GitProviderConfig, "git-provider-config", "", "Specify the Git provider configuration ID or alias") + cmd.Flags().StringArrayVar(flags.Labels, "label", []string{}, "Specify labels (e.g. --label 'label.key1=VALUE1' --label 'label.key2=VALUE2' ...)") cmd.MarkFlagsMutuallyExclusive("builder", "custom-image") cmd.MarkFlagsMutuallyExclusive("builder", "custom-image-user") @@ -38,38 +39,30 @@ func AddProjectConfigurationFlags(cmd *cobra.Command, flags ProjectConfiguration cmd.MarkFlagsMutuallyExclusive("devcontainer-path", "custom-image-user") cmd.MarkFlagsRequiredTogether("custom-image", "custom-image-user") - if multiProjectFlagException { - cmd.MarkFlagsMutuallyExclusive("multi-project", "custom-image") - cmd.MarkFlagsMutuallyExclusive("multi-project", "custom-image-user") - cmd.MarkFlagsMutuallyExclusive("multi-project", "devcontainer-path") - cmd.MarkFlagsMutuallyExclusive("multi-project", "builder") - cmd.MarkFlagsMutuallyExclusive("multi-project", "env") + if multiWorkspaceFlagException { + cmd.MarkFlagsMutuallyExclusive("multi-workspace", "custom-image") + cmd.MarkFlagsMutuallyExclusive("multi-workspace", "custom-image-user") + cmd.MarkFlagsMutuallyExclusive("multi-workspace", "devcontainer-path") + cmd.MarkFlagsMutuallyExclusive("multi-workspace", "builder") + cmd.MarkFlagsMutuallyExclusive("multi-workspace", "env") } } -func CheckAnyProjectConfigurationFlagSet(flags ProjectConfigurationFlags) bool { - return *flags.GitProviderConfig != "" || *flags.CustomImage != "" || *flags.CustomImageUser != "" || *flags.DevcontainerPath != "" || *flags.Builder != "" || len(*flags.EnvVars) > 0 +func CheckAnyWorkspaceConfigurationFlagSet(flags WorkspaceConfigurationFlags) bool { + return *flags.GitProviderConfig != "" || *flags.CustomImage != "" || *flags.CustomImageUser != "" || *flags.DevcontainerPath != "" || *flags.Builder != "" || len(*flags.EnvVars) > 0 || len(*flags.Labels) > 0 } -func IsProjectRunning(workspace *apiclient.WorkspaceDTO, projectName string) bool { - for _, project := range workspace.GetProjects() { - if project.GetName() == projectName { - return project.GetState().Uptime != 0 - } - } - return false -} +func MapKeyValue(arr []string) (map[string]string, error) { + result := map[string]string{} -func GetProjectProviderMetadata(workspace *apiclient.WorkspaceDTO, projectName string) (string, error) { - if workspace.Info != nil { - for _, project := range workspace.Info.Projects { - if project.Name == projectName { - if project.ProviderMetadata == nil { - return "", errors.New("project provider metadata is missing") - } - return *project.ProviderMetadata, nil - } + for _, str := range arr { + parts := strings.SplitN(str, "=", 2) + if len(parts) == 2 { + result[parts[0]] = parts[1] + } else { + return nil, fmt.Errorf("invalid format: %s", str) } } - return "", nil + + return result, nil } diff --git a/pkg/cmd/server/daemon/daemon.go b/pkg/cmd/common/daemon/daemon.go similarity index 86% rename from pkg/cmd/server/daemon/daemon.go rename to pkg/cmd/common/daemon/daemon.go index fc47f518e4..9feb3928b7 100644 --- a/pkg/cmd/server/daemon/daemon.go +++ b/pkg/cmd/common/daemon/daemon.go @@ -16,14 +16,14 @@ import ( "github.com/kardianos/service" ) -const serviceName = "DaytonaServerDaemon" - type program struct { service.Interface } -func Start(logFilePath string) error { - cfg, err := getServiceConfig() +var ErrDaemonNotInstalled = errors.New("daemon not installed") + +func Start(logFilePath string, svcConfig *service.Config) error { + cfg, err := getServiceConfig(svcConfig) if err != nil { return err } @@ -88,7 +88,7 @@ func Start(logFilePath string) error { return nil } - err = Stop() + err = Stop(svcConfig) if err != nil { return err } @@ -100,8 +100,8 @@ func Start(logFilePath string) error { } } -func Stop() error { - cfg, err := getServiceConfig() +func Stop(svcConfig *service.Config) error { + cfg, err := getServiceConfig(svcConfig) if err != nil { return err } @@ -115,7 +115,7 @@ func Stop() error { return err } if _, err := os.Stat(serviceFilePath); os.IsNotExist(err) { - return errors.New("daemon not installed. Run `daytona server` to start the server") + return ErrDaemonNotInstalled } err = s.Stop() @@ -126,7 +126,7 @@ func Stop() error { return s.Uninstall() } -func getServiceConfig() (*service.Config, error) { +func getServiceConfig(svcConfig *service.Config) (*service.Config, error) { if runtime.GOOS == "windows" { return nil, errors.New("daemon mode not supported on Windows") } @@ -136,13 +136,6 @@ func getServiceConfig() (*service.Config, error) { return nil, errors.New("could not determine user") } - svcConfig := &service.Config{ - Name: serviceName, - DisplayName: "Daytona Server", - Description: "Daytona Server daemon.", - Arguments: []string{"daemon-serve"}, - } - switch runtime.GOOS { case "linux": // Fix for running as root on Linux diff --git a/pkg/cmd/common/delete_workspace.go b/pkg/cmd/common/delete_workspace.go new file mode 100644 index 0000000000..3706d3cf19 --- /dev/null +++ b/pkg/cmd/common/delete_workspace.go @@ -0,0 +1,51 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package common + +import ( + "context" + "fmt" + + "github.com/daytonaio/daytona/cmd/daytona/config" + apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" + "github.com/daytonaio/daytona/pkg/apiclient" + views_util "github.com/daytonaio/daytona/pkg/views/util" +) + +func DeleteWorkspace(ctx context.Context, apiClient *apiclient.APIClient, workspaceId, workspaceName string, force bool) error { + message := fmt.Sprintf("Deleting workspace %s", workspaceName) + err := views_util.WithInlineSpinner(message, func() error { + res, err := apiClient.WorkspaceAPI.DeleteWorkspace(ctx, workspaceId).Force(force).Execute() + if err != nil { + return apiclient_util.HandleErrorResponse(res, err) + } + c, err := config.GetConfig() + if err != nil { + return err + } + + activeProfile, err := c.GetActiveProfile() + if err != nil { + return err + } + + err = config.RemoveSshEntries(activeProfile.Id, workspaceId) + if err != nil { + return err + } + + err = AwaitWorkspaceDeleted(workspaceId) + if err != nil { + return err + } + + return nil + }) + + if err != nil { + return err + } + + return nil +} diff --git a/pkg/cmd/common/get_gpg_key.go b/pkg/cmd/common/get_gpg_key.go new file mode 100644 index 0000000000..6d5a1da5f9 --- /dev/null +++ b/pkg/cmd/common/get_gpg_key.go @@ -0,0 +1,35 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package common + +import ( + "context" + + apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" + "github.com/daytonaio/daytona/pkg/apiclient" +) + +func GetGitProviderGpgKey(apiClient *apiclient.APIClient, ctx context.Context, providerConfigId *string) (*string, error) { + if providerConfigId == nil || *providerConfigId == "" { + return nil, nil + } + + var gpgKey *string + + gitProvider, res, err := apiClient.GitProviderAPI.FindGitProvider(ctx, *providerConfigId).Execute() + if err != nil { + return nil, apiclient_util.HandleErrorResponse(res, err) + } + + // Extract GPG key if present + if gitProvider != nil { + if gitProvider.SigningMethod != nil && gitProvider.SigningKey != nil { + if *gitProvider.SigningMethod == apiclient.SigningMethodGPG { + gpgKey = gitProvider.SigningKey + } + } + } + + return gpgKey, nil +} diff --git a/pkg/cmd/common/get_runner.go b/pkg/cmd/common/get_runner.go new file mode 100644 index 0000000000..9e8ab58de7 --- /dev/null +++ b/pkg/cmd/common/get_runner.go @@ -0,0 +1,50 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package common + +import ( + "context" + + "github.com/daytonaio/daytona/cmd/daytona/config" + apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" + "github.com/daytonaio/daytona/pkg/apiclient" + "github.com/daytonaio/daytona/pkg/common" + runner "github.com/daytonaio/daytona/pkg/views/server/runner/selection" + views_util "github.com/daytonaio/daytona/pkg/views/util" +) + +func GetRunnerFlow(apiClient *apiclient.APIClient, action string) (*runner.RunnerView, error) { + ctx := context.Background() + + c, err := config.GetConfig() + if err != nil { + return nil, err + } + + activeProfile, err := c.GetActiveProfile() + if err != nil { + return nil, err + } + + runners, res, err := apiClient.RunnerAPI.ListRunners(ctx).Execute() + if err != nil { + return nil, apiclient_util.HandleErrorResponse(res, err) + } + + if len(runners) == 0 { + views_util.NotifyEmptyRunnerList(true) + return nil, nil + } + + selectedRunner, err := runner.GetRunnerFromPrompt(runners, activeProfile.Name, action) + if err != nil { + if common.IsCtrlCAbort(err) { + return nil, nil + } else { + return nil, err + } + } + + return selectedRunner, nil +} diff --git a/pkg/cmd/common/open_ide.go b/pkg/cmd/common/open_ide.go new file mode 100644 index 0000000000..e74bee2cb9 --- /dev/null +++ b/pkg/cmd/common/open_ide.go @@ -0,0 +1,65 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package common + +import ( + "errors" + + "github.com/daytonaio/daytona/cmd/daytona/config" + "github.com/daytonaio/daytona/internal/jetbrains" + "github.com/daytonaio/daytona/pkg/ide" + "github.com/daytonaio/daytona/pkg/telemetry" + + log "github.com/sirupsen/logrus" +) + +func OpenIDE(ideId string, activeProfile config.Profile, workspaceId string, workspaceProviderMetadata string, yesFlag bool, gpgKey *string) error { + var err error + switch ideId { + case "vscode": + err = ide.OpenVSCode(activeProfile, workspaceId, workspaceProviderMetadata, gpgKey) + case "code-insiders": + err = ide.OpenVSCodeInsiders(activeProfile, workspaceId, workspaceProviderMetadata, gpgKey) + case "ssh": + err = ide.OpenTerminalSsh(activeProfile, workspaceId, gpgKey, nil) + case "browser": + err = ide.OpenBrowserIDE(activeProfile, workspaceId, workspaceProviderMetadata, gpgKey) + case "codium": + err = ide.OpenVScodium(activeProfile, workspaceId, workspaceProviderMetadata, gpgKey) + case "codium-insiders": + err = ide.OpenVScodiumInsiders(activeProfile, workspaceId, workspaceProviderMetadata, gpgKey) + case "cursor": + err = ide.OpenCursor(activeProfile, workspaceId, workspaceProviderMetadata, gpgKey) + case "jupyter": + err = ide.OpenJupyterIDE(activeProfile, workspaceId, workspaceProviderMetadata, yesFlag, gpgKey) + case "fleet": + err = ide.OpenFleet(activeProfile, workspaceId, gpgKey) + case "positron": + err = ide.OpenPositron(activeProfile, workspaceId, workspaceProviderMetadata, gpgKey) + case "zed": + err = ide.OpenZed(activeProfile, workspaceId, gpgKey) + case "windsurf": + err = ide.OpenWindsurf(activeProfile, workspaceId, workspaceProviderMetadata, gpgKey) + default: + _, ok := jetbrains.GetIdes()[jetbrains.Id(ideId)] + if ok { + err = ide.OpenJetbrainsIDE(activeProfile, ideId, workspaceId, gpgKey) + } else { + return errors.New("invalid IDE. Please choose one by running `daytona ide`") + } + } + + eventName := telemetry.CliEventWorkspaceOpened + if err != nil { + eventName = telemetry.CliEventWorkspaceOpenFailed + } + + event := telemetry.NewCliEvent(eventName, nil, []string{}, err, map[string]interface{}{"ide": ideId}) + telemetryErr := TrackTelemetryEvent(event, config.GetClientId()) + if telemetryErr != nil { + log.Trace(telemetryErr) + } + + return err +} diff --git a/pkg/cmd/common/polling.go b/pkg/cmd/common/polling.go new file mode 100644 index 0000000000..d75b949f3c --- /dev/null +++ b/pkg/cmd/common/polling.go @@ -0,0 +1,138 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package common + +import ( + "context" + "errors" + "net/http" + "time" + + apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" + "github.com/daytonaio/daytona/pkg/apiclient" +) + +func AwaitWorkspaceState(workspaceId string, stateName apiclient.ModelsResourceStateName) error { + ctx := context.Background() + + apiClient, err := apiclient_util.GetApiClient(nil) + if err != nil { + return err + } + + for { + state, _, err := apiClient.WorkspaceAPI.GetWorkspaceState(ctx, workspaceId).Execute() + if err != nil { + return err + } + if state.Name == stateName { + return nil + } + if state.Name == apiclient.ResourceStateNameError { + var errorMessage string + if state.Error != nil { + errorMessage = *state.Error + } + return errors.New(errorMessage) + } + time.Sleep(100 * time.Millisecond) + } +} + +func AwaitTargetState(targetId string, stateName apiclient.ModelsResourceStateName) error { + ctx := context.Background() + + apiClient, err := apiclient_util.GetApiClient(nil) + if err != nil { + return err + } + + for { + state, _, err := apiClient.TargetAPI.GetTargetState(ctx, targetId).Execute() + if err != nil { + return err + } + + if state.Name == stateName || state.Name == apiclient.ResourceStateNameUndefined { + return nil + } + + if state.Name == apiclient.ResourceStateNameError { + var errorMessage string + if state.Error != nil { + errorMessage = *state.Error + } + return errors.New(errorMessage) + } + time.Sleep(100 * time.Millisecond) + } +} + +func AwaitProviderInstalled(runnerId, providerName, version string) error { + ctx := context.Background() + + apiClient, err := apiclient_util.GetApiClient(nil) + if err != nil { + return err + } + + for { + providers, res, err := apiClient.ProviderAPI.GetRunnerProviders(ctx, runnerId).Execute() + if err != nil { + return apiclient_util.HandleErrorResponse(res, err) + } + + if providers == nil { + continue + } + + for _, provider := range providers { + if provider.Name == providerName && provider.Version == version { + return nil + } + } + + time.Sleep(100 * time.Millisecond) + } +} + +func AwaitWorkspaceDeleted(workspaceId string) error { + ctx := context.Background() + + apiClient, err := apiclient_util.GetApiClient(nil) + if err != nil { + return err + } + + for { + _, res, err := apiClient.WorkspaceAPI.GetWorkspaceState(ctx, workspaceId).Execute() + if err != nil { + if res != nil && res.StatusCode == http.StatusNotFound { + return nil + } + return err + } + time.Sleep(100 * time.Millisecond) + } +} + +func AwaitTargetDeleted(workspaceId string) error { + ctx := context.Background() + + apiClient, err := apiclient_util.GetApiClient(nil) + if err != nil { + return err + } + + for { + _, res, err := apiClient.TargetAPI.GetTargetState(ctx, workspaceId).Execute() + if err != nil { + if res != nil && res.StatusCode == http.StatusNotFound { + return nil + } + return err + } + time.Sleep(100 * time.Millisecond) + } +} diff --git a/pkg/cmd/common/telemetry.go b/pkg/cmd/common/telemetry.go new file mode 100644 index 0000000000..f6a92a7ffc --- /dev/null +++ b/pkg/cmd/common/telemetry.go @@ -0,0 +1,50 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package common + +import ( + "github.com/daytonaio/daytona/cmd/daytona/config" + "github.com/daytonaio/daytona/internal" + "github.com/daytonaio/daytona/pkg/common" + "github.com/daytonaio/daytona/pkg/posthogservice" + "github.com/daytonaio/daytona/pkg/telemetry" +) + +var telemetryService telemetry.TelemetryService + +func TrackTelemetryEvent(event telemetry.Event, clientId string) error { + if telemetryService == nil { + return nil + } + + return telemetryService.Track(event, clientId) +} + +func CloseTelemetryService() error { + if telemetryService == nil { + return nil + } + + return telemetryService.Close() +} + +func init() { + telemetryEnabled := config.TelemetryEnabled() + + if !telemetryEnabled { + return + } + + source := telemetry.CLI_SOURCE + if common.AgentMode() { + source = telemetry.CLI_AGENT_MODE_SOURCE + } + + telemetryService = posthogservice.NewTelemetryService(posthogservice.PosthogServiceConfig{ + ApiKey: internal.PosthogApiKey, + Endpoint: internal.PosthogEndpoint, + Version: internal.Version, + Source: source, + }) +} diff --git a/pkg/cmd/common/websocket_log_reader.go b/pkg/cmd/common/websocket_log_reader.go new file mode 100644 index 0000000000..262df9756b --- /dev/null +++ b/pkg/cmd/common/websocket_log_reader.go @@ -0,0 +1,199 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package common + +import ( + "context" + "fmt" + "time" + + "github.com/daytonaio/daytona/internal/util" + "github.com/daytonaio/daytona/internal/util/apiclient" + "github.com/daytonaio/daytona/pkg/logs" + logs_view "github.com/daytonaio/daytona/pkg/views/logs" + "github.com/gorilla/websocket" + log "github.com/sirupsen/logrus" +) + +type ReadLogParams struct { + Id string + Label *string + ServerUrl string + ApiKey string + SkipPrefixLengthSetup bool + Index *int + Follow *bool + From *time.Time +} + +var targetLogsStarted bool + +func ReadTargetLogs(ctx context.Context, params ReadLogParams) { + checkAndSetupLongestPrefixLength(params.SkipPrefixLengthSetup, params.Id, params.Label) + + query := "" + if params.Follow != nil && *params.Follow { + query = "follow=true" + } + + for { + ws, res, err := util.GetWebsocketConn(ctx, fmt.Sprintf("/log/target/%s", params.Id), params.ServerUrl, params.ApiKey, &query) + // We want to retry getting the logs if it fails + if err != nil { + log.Trace(apiclient.HandleErrorResponse(res, err)) + time.Sleep(250 * time.Millisecond) + continue + } + + readJSONLog(ctx, ws, logs_view.STATIC_INDEX, params.From) + ws.Close() + break + } +} + +func ReadWorkspaceLogs(ctx context.Context, params ReadLogParams) { + checkAndSetupLongestPrefixLength(params.SkipPrefixLengthSetup, params.Id, params.Label) + + query := "" + if params.Follow != nil && *params.Follow { + query = "follow=true" + } + + for { + ws, res, err := util.GetWebsocketConn(ctx, fmt.Sprintf("/log/workspace/%s", params.Id), params.ServerUrl, params.ApiKey, &query) + // We want to retry getting the logs if it fails + if err != nil { + log.Trace(apiclient.HandleErrorResponse(res, err)) + time.Sleep(500 * time.Millisecond) + continue + } + + index := 0 + if params.Index != nil { + index = *params.Index + } + + readJSONLog(ctx, ws, index, params.From) + ws.Close() + break + } +} + +func ReadBuildLogs(ctx context.Context, params ReadLogParams) { + checkAndSetupLongestPrefixLength(params.SkipPrefixLengthSetup, params.Id, params.Label) + + for { + query := "" + if params.Follow != nil && *params.Follow { + query = "follow=true" + } + + ws, res, err := util.GetWebsocketConn(ctx, fmt.Sprintf("/log/build/%s", params.Id), params.ServerUrl, params.ApiKey, &query) + // We want to retry getting the logs if it fails + if err != nil { + log.Trace(apiclient.HandleErrorResponse(res, err)) + time.Sleep(250 * time.Millisecond) + continue + } + + readJSONLog(ctx, ws, logs_view.FIRST_WORKSPACE_INDEX, nil) + ws.Close() + break + } +} + +func ReadRunnerLogs(ctx context.Context, params ReadLogParams) { + checkAndSetupLongestPrefixLength(params.SkipPrefixLengthSetup, params.Id, params.Label) + + for { + query := "" + if params.Follow != nil && *params.Follow { + query = "follow=true" + } + + ws, res, err := util.GetWebsocketConn(ctx, fmt.Sprintf("/log/runner/%s", params.Id), params.ServerUrl, params.ApiKey, &query) + // We want to retry getting the logs if it fails + if err != nil { + log.Trace(apiclient.HandleErrorResponse(res, err)) + time.Sleep(250 * time.Millisecond) + continue + } + + readJSONLog(ctx, ws, logs_view.FIRST_WORKSPACE_INDEX, nil) + ws.Close() + break + } +} + +func readJSONLog(ctx context.Context, ws *websocket.Conn, index int, from *time.Time) { + logEntriesChan := make(chan logs.LogEntry) + readErr := make(chan error) + go func() { + for { + var logEntry logs.LogEntry + + err := ws.ReadJSON(&logEntry) + + // An empty entry will be sent from the server on close/EOF + // We don't want to print that + if logEntry != (logs.LogEntry{}) { + logEntriesChan <- logEntry + } + + if err != nil { + if websocket.IsUnexpectedCloseError(err, websocket.CloseNormalClosure) { + log.Error(err) + } + readErr <- err + return + } + } + }() + + for { + select { + case <-ctx.Done(): + return + case logEntry := <-logEntriesChan: + if from != nil { + parsedTime, err := time.Parse(time.RFC3339Nano, logEntry.Time) + if err != nil { + log.Trace(err) + } + + if parsedTime.After(*from) || parsedTime.Equal(*from) { + logs_view.DisplayLogEntry(logEntry, index) + } + } else { + logs_view.DisplayLogEntry(logEntry, index) + } + + case err := <-readErr: + if err != nil { + err := ws.WriteControl(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""), time.Now().Add(time.Second)) + if err != nil { + log.Trace(err) + } + ws.Close() + return + } + } + + if !targetLogsStarted && index == logs_view.STATIC_INDEX { + targetLogsStarted = true + } + } +} + +func checkAndSetupLongestPrefixLength(skipSetup bool, id string, label *string) { + if skipSetup { + return + } + + name := id + if label != nil { + name = *label + } + logs_view.SetupLongestPrefixLength([]string{name}) +} diff --git a/pkg/cmd/common/workspace_autocompletion.go b/pkg/cmd/common/workspace_autocompletion.go new file mode 100644 index 0000000000..219dc35f1e --- /dev/null +++ b/pkg/cmd/common/workspace_autocompletion.go @@ -0,0 +1,59 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package common + +import ( + "context" + + apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" + "github.com/daytonaio/daytona/pkg/apiclient" + "github.com/spf13/cobra" +) + +func GetWorkspaceNameCompletions() ([]string, cobra.ShellCompDirective) { + ctx := context.Background() + apiClient, err := apiclient_util.GetApiClient(nil) + if err != nil { + return nil, cobra.ShellCompDirectiveNoFileComp + } + + workspaceList, _, err := apiClient.WorkspaceAPI.ListWorkspaces(ctx).Execute() + if err != nil { + return nil, cobra.ShellCompDirectiveNoFileComp + } + + var choices []string + for _, v := range workspaceList { + choices = append(choices, v.Name) + } + + return choices, cobra.ShellCompDirectiveNoFileComp +} + +func GetAllWorkspacesByState(state apiclient.ModelsResourceStateName) ([]string, cobra.ShellCompDirective) { + ctx := context.Background() + apiClient, err := apiclient_util.GetApiClient(nil) + if err != nil { + return nil, cobra.ShellCompDirectiveNoFileComp + } + + workspaceList, _, err := apiClient.WorkspaceAPI.ListWorkspaces(ctx).Execute() + if err != nil { + return nil, cobra.ShellCompDirectiveNoFileComp + } + + var choices []string + for _, workspace := range workspaceList { + if state == apiclient.ResourceStateNameStarted { + choices = append(choices, workspace.Name) + break + } + if state == apiclient.ResourceStateNameStopped { + choices = append(choices, workspace.Name) + break + } + } + + return choices, cobra.ShellCompDirectiveNoFileComp +} diff --git a/pkg/cmd/config.go b/pkg/cmd/config.go index 7992e0b33e..0d838fe9d6 100644 --- a/pkg/cmd/config.go +++ b/pkg/cmd/config.go @@ -13,10 +13,9 @@ import ( var showApiKeysFlag bool var configCmd = &cobra.Command{ - Use: "config", - Short: "Output Daytona configuration", - Aliases: []string{"cfg"}, - Args: cobra.NoArgs, + Use: "config", + Short: "Output Daytona configuration", + Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { c, err := config.GetConfig() if err != nil { diff --git a/pkg/cmd/containerregistry/containerregistry.go b/pkg/cmd/containerregistry/containerregistry.go deleted file mode 100644 index 32241ee0c7..0000000000 --- a/pkg/cmd/containerregistry/containerregistry.go +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package containerregistry - -import ( - "github.com/daytonaio/daytona/internal/util" - "github.com/spf13/cobra" -) - -var ContainerRegistryCmd = &cobra.Command{ - Use: "container-registry", - Aliases: []string{"container-registries", "cr"}, - Short: "Manage container registries", - GroupID: util.SERVER_GROUP, -} - -func init() { - ContainerRegistryCmd.AddCommand(containerRegistryListCmd) - ContainerRegistryCmd.AddCommand(containerRegistrySetCmd) - ContainerRegistryCmd.AddCommand(containerRegistryDeleteCmd) -} diff --git a/pkg/cmd/containerregistry/delete.go b/pkg/cmd/containerregistry/delete.go deleted file mode 100644 index 3dd952cd8d..0000000000 --- a/pkg/cmd/containerregistry/delete.go +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package containerregistry - -import ( - "context" - "net/url" - - "github.com/daytonaio/daytona/cmd/daytona/config" - apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" - "github.com/daytonaio/daytona/pkg/apiclient" - "github.com/daytonaio/daytona/pkg/common" - "github.com/daytonaio/daytona/pkg/views" - containerregistry_view "github.com/daytonaio/daytona/pkg/views/containerregistry" - views_util "github.com/daytonaio/daytona/pkg/views/util" - "github.com/spf13/cobra" -) - -var containerRegistryDeleteCmd = &cobra.Command{ - Use: "delete", - Aliases: []string{"remove", "rm"}, - Short: "Delete a container registry", - Args: cobra.RangeArgs(0, 2), - RunE: func(cmd *cobra.Command, args []string) error { - var registryDto *apiclient.ContainerRegistry - var selectedServer string - - apiClient, err := apiclient_util.GetApiClient(nil) - if err != nil { - return err - } - - if len(args) == 0 { - c, err := config.GetConfig() - if err != nil { - return err - } - - activeProfile, err := c.GetActiveProfile() - if err != nil { - return err - } - - containerRegistries, res, err := apiClient.ContainerRegistryAPI.ListContainerRegistries(context.Background()).Execute() - if err != nil { - return apiclient_util.HandleErrorResponse(res, err) - } - - if len(containerRegistries) == 0 { - views_util.NotifyEmptyContainerRegistryList(false) - return nil - } - - registryDto, err = containerregistry_view.GetRegistryFromPrompt(containerRegistries, activeProfile.Name, false) - if err != nil { - if common.IsCtrlCAbort(err) { - return nil - } else { - return err - } - } - - selectedServer = registryDto.Server - } else { - selectedServer = args[0] - } - - res, err := apiClient.ContainerRegistryAPI.RemoveContainerRegistry(context.Background(), url.QueryEscape(selectedServer)).Execute() - if err != nil { - return apiclient_util.HandleErrorResponse(res, err) - } - - views.RenderInfoMessage("Container registry deleted successfully") - return nil - }, -} diff --git a/pkg/cmd/containerregistry/list.go b/pkg/cmd/containerregistry/list.go deleted file mode 100644 index c54710f460..0000000000 --- a/pkg/cmd/containerregistry/list.go +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package containerregistry - -import ( - "context" - - "github.com/daytonaio/daytona/internal/util/apiclient" - apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" - "github.com/daytonaio/daytona/pkg/cmd/format" - containerregistry_view "github.com/daytonaio/daytona/pkg/views/containerregistry/list" - "github.com/spf13/cobra" -) - -var containerRegistryListCmd = &cobra.Command{ - Use: "list", - Short: "Lists container registries", - Aliases: []string{"ls"}, - Args: cobra.NoArgs, - RunE: func(cmd *cobra.Command, args []string) error { - apiClient, err := apiclient_util.GetApiClient(nil) - if err != nil { - return err - } - - containerRegistries, res, err := apiClient.ContainerRegistryAPI.ListContainerRegistries(context.Background()).Execute() - if err != nil { - return apiclient.HandleErrorResponse(res, err) - } - - if format.FormatFlag != "" { - formattedData := format.NewFormatter(containerRegistries) - formattedData.Print() - return nil - } - - containerregistry_view.ListRegistries(containerRegistries) - return nil - }, -} - -func init() { - format.RegisterFormatFlag(containerRegistryListCmd) -} diff --git a/pkg/cmd/containerregistry/set.go b/pkg/cmd/containerregistry/set.go deleted file mode 100644 index aa81686be6..0000000000 --- a/pkg/cmd/containerregistry/set.go +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package containerregistry - -import ( - "context" - "net/url" - - "github.com/daytonaio/daytona/cmd/daytona/config" - apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" - "github.com/daytonaio/daytona/pkg/apiclient" - "github.com/daytonaio/daytona/pkg/common" - "github.com/daytonaio/daytona/pkg/views" - containerregistry_view "github.com/daytonaio/daytona/pkg/views/containerregistry" - "github.com/spf13/cobra" -) - -var containerRegistrySetCmd = &cobra.Command{ - Use: "set", - Short: "Set container registry", - Args: cobra.NoArgs, - Aliases: []string{"add", "update", "register"}, - RunE: func(cmd *cobra.Command, args []string) error { - var registryDto *apiclient.ContainerRegistry - selectedServer := serverFlag - - c, err := config.GetConfig() - if err != nil { - return err - } - - activeProfile, err := c.GetActiveProfile() - if err != nil { - return err - } - - registryView := containerregistry_view.RegistryView{ - Server: serverFlag, - Username: usernameFlag, - Password: passwordFlag, - } - - apiClient, err := apiclient_util.GetApiClient(nil) - if err != nil { - return err - } - - containerRegistries, res, err := apiClient.ContainerRegistryAPI.ListContainerRegistries(context.Background()).Execute() - if err != nil { - return apiclient_util.HandleErrorResponse(res, err) - } - - if serverFlag == "" || usernameFlag == "" || passwordFlag == "" { - if len(containerRegistries) == 0 { - containerregistry_view.RegistryCreationView(®istryView, containerRegistries, false) - selectedServer = registryView.Server - } else { - registryDto, err := containerregistry_view.GetRegistryFromPrompt(containerRegistries, activeProfile.Name, true) - if err != nil { - if common.IsCtrlCAbort(err) { - return nil - } else { - return err - } - } - - editing := true - selectedServer = registryDto.Server - - if registryDto.Server == containerregistry_view.NewRegistryServerIdentifier { - editing = false - registryView.Server, registryView.Username, registryView.Password = "", "", "" - } else { - registryView.Server = registryDto.Server - registryView.Username = registryDto.Username - registryView.Password = registryDto.Password - } - - containerregistry_view.RegistryCreationView(®istryView, containerRegistries, editing) - } - } - - registryDto = &apiclient.ContainerRegistry{ - Server: registryView.Server, - Username: registryView.Username, - Password: registryView.Password, - } - - res, err = apiClient.ContainerRegistryAPI.SetContainerRegistry(context.Background(), url.QueryEscape(selectedServer)).ContainerRegistry(*registryDto).Execute() - if err != nil { - return apiclient_util.HandleErrorResponse(res, err) - } - - views.RenderInfoMessage("Registry set successfully") - return nil - }, -} - -var serverFlag string -var usernameFlag string -var passwordFlag string - -func init() { - containerRegistrySetCmd.Flags().StringVarP(&serverFlag, "server", "s", "", "Server") - containerRegistrySetCmd.Flags().StringVarP(&usernameFlag, "username", "u", "", "Username") - containerRegistrySetCmd.Flags().StringVarP(&passwordFlag, "password", "p", "", "Password") -} diff --git a/pkg/cmd/env/delete.go b/pkg/cmd/env/delete.go new file mode 100644 index 0000000000..8ad42e0e2d --- /dev/null +++ b/pkg/cmd/env/delete.go @@ -0,0 +1,55 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package env + +import ( + "context" + + apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" + "github.com/daytonaio/daytona/pkg/cmd/common" + "github.com/daytonaio/daytona/pkg/views" + "github.com/daytonaio/daytona/pkg/views/env" + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" +) + +var deleteCmd = &cobra.Command{ + Use: "delete [KEY]...", + Short: "Delete server environment variables", + Aliases: common.GetAliases("delete"), + RunE: func(cmd *cobra.Command, args []string) error { + keys := []string{} + + ctx := context.Background() + + apiClient, err := apiclient_util.GetApiClient(nil) + if err != nil { + return err + } + + if len(args) > 0 { + keys = args + } else { + selectedEnvVars, err := env.DeleteEnvVarsView(ctx, *apiClient) + if err != nil { + return err + } + + for _, envVar := range selectedEnvVars { + keys = append(keys, envVar.Key) + } + } + + for _, key := range keys { + res, err := apiClient.EnvVarAPI.DeleteEnvironmentVariable(ctx, key).Execute() + if err != nil { + log.Error(apiclient_util.HandleErrorResponse(res, err)) + } + } + + views.RenderInfoMessageBold("Server environment variables have been successfully removed") + + return nil + }, +} diff --git a/pkg/cmd/profiledata/env/env.go b/pkg/cmd/env/env.go similarity index 62% rename from pkg/cmd/profiledata/env/env.go rename to pkg/cmd/env/env.go index d22ea3d209..2056ab35e4 100644 --- a/pkg/cmd/profiledata/env/env.go +++ b/pkg/cmd/env/env.go @@ -10,11 +10,13 @@ import ( var EnvCmd = &cobra.Command{ Use: "env", - Short: "Manage profile environment variables that are added to all workspaces", - GroupID: util.PROFILE_GROUP, + Short: "Manage server environment variables that are added to all targets and workspaces", + Args: cobra.NoArgs, + GroupID: util.SERVER_GROUP, } func init() { EnvCmd.AddCommand(setCmd) EnvCmd.AddCommand(listCmd) + EnvCmd.AddCommand(deleteCmd) } diff --git a/pkg/cmd/env/list.go b/pkg/cmd/env/list.go new file mode 100644 index 0000000000..a7f5d7da0d --- /dev/null +++ b/pkg/cmd/env/list.go @@ -0,0 +1,60 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package env + +import ( + "context" + + apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" + "github.com/daytonaio/daytona/pkg/apiclient" + "github.com/daytonaio/daytona/pkg/cmd/common" + "github.com/daytonaio/daytona/pkg/cmd/format" + "github.com/daytonaio/daytona/pkg/views/env" + "github.com/spf13/cobra" +) + +var showValuesFlag bool + +var listCmd = &cobra.Command{ + Use: "list", + Short: "List server environment variables", + Aliases: common.GetAliases("list"), + RunE: func(cmd *cobra.Command, args []string) error { + apiClient, err := apiclient_util.GetApiClient(nil) + if err != nil { + return err + } + ctx := context.Background() + + envVars, res, err := apiClient.EnvVarAPI.ListEnvironmentVariables(ctx).Execute() + if err != nil { + return apiclient_util.HandleErrorResponse(res, err) + } + + if !showValuesFlag { + for i := range envVars { + envVars[i].Value = "****************" + } + } + + if format.FormatFlag != "" { + if envVars == nil { + envVars = []apiclient.EnvironmentVariable{} + } + + formattedData := format.NewFormatter(envVars) + formattedData.Print() + return nil + } + + env.List(envVars) + return nil + }, +} + +func init() { + format.RegisterFormatFlag(listCmd) + + listCmd.Flags().BoolVarP(&showValuesFlag, "show-values", "v", false, "Show environment variable values") +} diff --git a/pkg/cmd/env/set.go b/pkg/cmd/env/set.go new file mode 100644 index 0000000000..90bb20c7e7 --- /dev/null +++ b/pkg/cmd/env/set.go @@ -0,0 +1,61 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package env + +import ( + "context" + "fmt" + "strings" + + apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" + "github.com/daytonaio/daytona/pkg/apiclient" + "github.com/daytonaio/daytona/pkg/views" + "github.com/daytonaio/daytona/pkg/views/env" + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" +) + +var setCmd = &cobra.Command{ + Use: "set [KEY=VALUE]...", + Short: "Set server environment variables", + RunE: func(cmd *cobra.Command, args []string) error { + envVarsMap := make(map[string]string) + + if len(args) > 0 { + for _, arg := range args { + kv := strings.Split(arg, "=") + if len(kv) != 2 { + return fmt.Errorf("invalid key-value pair: %s", arg) + } + envVarsMap[kv[0]] = kv[1] + } + } else { + err := env.SetEnvVarsView(&envVarsMap) + if err != nil { + return err + } + } + + ctx := context.Background() + + apiClient, err := apiclient_util.GetApiClient(nil) + if err != nil { + return err + } + + for key, value := range envVarsMap { + res, err := apiClient.EnvVarAPI.SaveEnvironmentVariable(ctx).EnvironmentVariable(apiclient.EnvironmentVariable{ + Key: key, + Value: value, + }).Execute() + if err != nil { + log.Error(apiclient_util.HandleErrorResponse(res, err)) + } + } + + views.RenderInfoMessageBold("Server environment variables have been set successfully") + + return nil + }, +} diff --git a/pkg/cmd/generatedocs.go b/pkg/cmd/generatedocs.go index 2cbb4dca28..6ca84ab2a5 100644 --- a/pkg/cmd/generatedocs.go +++ b/pkg/cmd/generatedocs.go @@ -18,6 +18,7 @@ var defaultDirectory = "docs" var generateDocsCmd = &cobra.Command{ Use: "generate-docs", Short: "Generate documentation for the Daytona CLI", + Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { directory, err := cmd.Flags().GetString("directory") if err != nil { diff --git a/pkg/cmd/gitprovider/add.go b/pkg/cmd/gitprovider/create.go similarity index 80% rename from pkg/cmd/gitprovider/add.go rename to pkg/cmd/gitprovider/create.go index a5341664cb..1fc49bda97 100644 --- a/pkg/cmd/gitprovider/add.go +++ b/pkg/cmd/gitprovider/create.go @@ -13,16 +13,16 @@ import ( "github.com/daytonaio/daytona/internal/util" apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" "github.com/daytonaio/daytona/pkg/apiclient" + "github.com/daytonaio/daytona/pkg/cmd/common" "github.com/daytonaio/daytona/pkg/views" gitprovider_view "github.com/daytonaio/daytona/pkg/views/gitprovider" "github.com/spf13/cobra" ) -var GitProviderAddCmd = &cobra.Command{ - Use: "add [GIT_PROVIDER_ID]", - Aliases: []string{"new", "register"}, - Short: "Register a Git provider", - Args: cobra.RangeArgs(0, 1), +var GitProviderCreateCmd = &cobra.Command{ + Use: "create [GIT_PROVIDER_ID]", + Short: "Create a Git provider config", + Aliases: common.GetAliases("create"), RunE: func(cmd *cobra.Command, args []string) error { ctx := context.Background() @@ -131,7 +131,7 @@ var GitProviderAddCmd = &cobra.Command{ return nil } - res, err = apiClient.GitProviderAPI.SetGitProvider(ctx).GitProviderConfig(setGitProviderConfig).Execute() + res, err = apiClient.GitProviderAPI.SaveGitProvider(ctx).GitProviderConfig(setGitProviderConfig).Execute() if err != nil { return apiclient_util.HandleErrorResponse(res, err) } @@ -149,11 +149,11 @@ var signingMethodFlag string var signingKeyFlag string func init() { - GitProviderAddCmd.Flags().StringVarP(&aliasFlag, "alias", "a", "", "Alias") - GitProviderAddCmd.Flags().StringVarP(&usernameFlag, "username", "u", "", "Username") - GitProviderAddCmd.Flags().StringVarP(&baseApiUrlFlag, "base-api-url", "b", "", "Base API Url") - GitProviderAddCmd.Flags().StringVarP(&tokenFlag, "token", "t", "", "Personal Access Token") - GitProviderAddCmd.Flags().StringVarP(&signingMethodFlag, "signing-method", "s", "", "Signing Method (ssh, gpg)") - GitProviderAddCmd.Flags().StringVarP(&signingKeyFlag, "signing-key", "k", "", "Signing Key") - GitProviderAddCmd.MarkFlagsRequiredTogether("signing-method", "signing-key") + GitProviderCreateCmd.Flags().StringVarP(&aliasFlag, "alias", "a", "", "Alias") + GitProviderCreateCmd.Flags().StringVarP(&usernameFlag, "username", "u", "", "Username") + GitProviderCreateCmd.Flags().StringVarP(&baseApiUrlFlag, "base-api-url", "b", "", "Base API Url") + GitProviderCreateCmd.Flags().StringVarP(&tokenFlag, "token", "t", "", "Personal Access Token") + GitProviderCreateCmd.Flags().StringVarP(&signingMethodFlag, "signing-method", "s", "", "Signing Method (ssh, gpg)") + GitProviderCreateCmd.Flags().StringVarP(&signingKeyFlag, "signing-key", "k", "", "Signing Key") + GitProviderCreateCmd.MarkFlagsRequiredTogether("signing-method", "signing-key") } diff --git a/pkg/cmd/gitprovider/delete.go b/pkg/cmd/gitprovider/delete.go index af357b0db3..d1179ff357 100644 --- a/pkg/cmd/gitprovider/delete.go +++ b/pkg/cmd/gitprovider/delete.go @@ -10,16 +10,17 @@ import ( "github.com/charmbracelet/huh" apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" "github.com/daytonaio/daytona/pkg/apiclient" + "github.com/daytonaio/daytona/pkg/cmd/common" "github.com/daytonaio/daytona/pkg/views" + "github.com/daytonaio/daytona/pkg/views/selection" views_util "github.com/daytonaio/daytona/pkg/views/util" - "github.com/daytonaio/daytona/pkg/views/workspace/selection" "github.com/spf13/cobra" ) -var gitProviderDeleteCmd = &cobra.Command{ +var deleteCmd = &cobra.Command{ Use: "delete", - Aliases: []string{"remove", "rm"}, - Short: "Unregister a Git provider", + Short: "Delete a Git provider config", + Aliases: common.GetAliases("delete"), RunE: func(cmd *cobra.Command, args []string) error { ctx := context.Background() @@ -40,7 +41,7 @@ var gitProviderDeleteCmd = &cobra.Command{ if allFlag { if yesFlag { - err = removeAllGitProviders(gitProviders, apiClient) + err = deleteAllGitProviders(gitProviders, apiClient) if err != nil { return err } @@ -48,8 +49,8 @@ var gitProviderDeleteCmd = &cobra.Command{ form := huh.NewForm( huh.NewGroup( huh.NewConfirm(). - Title("Remove all git providers?"). - Description("Are you sure you want to remove all git providers?"). + Title("Delete all git providers?"). + Description("Are you sure you want to delete all git providers?"). Value(&yesFlag), ), ).WithTheme(views.GetCustomTheme()) @@ -59,7 +60,7 @@ var gitProviderDeleteCmd = &cobra.Command{ } if yesFlag { - err = removeAllGitProviders(gitProviders, apiClient) + err = deleteAllGitProviders(gitProviders, apiClient) if err != nil { return err } @@ -73,7 +74,7 @@ var gitProviderDeleteCmd = &cobra.Command{ selectedGitProvider := selection.GetGitProviderConfigFromPrompt(selection.GetGitProviderConfigParams{ GitProviderConfigs: gitProviders, - ActionVerb: "Remove", + ActionVerb: "Delete", }) if selectedGitProvider == nil { @@ -85,8 +86,8 @@ var gitProviderDeleteCmd = &cobra.Command{ form := huh.NewForm( huh.NewGroup( huh.NewConfirm(). - Title(fmt.Sprintf("Remove git provider: %s?", selectedGitProviderText)). - Description(fmt.Sprintf("Are you sure you want to remove the git provider: %s?", selectedGitProviderText)). + Title(fmt.Sprintf("Delete git provider: %s?", selectedGitProviderText)). + Description(fmt.Sprintf("Are you sure you want to delete the Git provider: %s?", selectedGitProviderText)). Value(&yesFlag), ), ).WithTheme(views.GetCustomTheme()) @@ -100,12 +101,12 @@ var gitProviderDeleteCmd = &cobra.Command{ if !yesFlag { fmt.Println("Operation canceled.") } else { - _, err = apiClient.GitProviderAPI.RemoveGitProvider(ctx, selectedGitProvider.Id).Execute() + _, err = apiClient.GitProviderAPI.DeleteGitProvider(ctx, selectedGitProvider.Id).Execute() if err != nil { return err } - views.RenderInfoMessage("Git provider has been removed") + views.RenderInfoMessage("Git provider has been deleted") } return nil @@ -116,14 +117,14 @@ var allFlag bool var yesFlag bool func init() { - gitProviderDeleteCmd.Flags().BoolVarP(&allFlag, "all", "a", false, "Remove all Git providers") - gitProviderDeleteCmd.Flags().BoolVarP(&yesFlag, "yes", "y", false, "Confirm deletion without prompt") + deleteCmd.Flags().BoolVarP(&allFlag, "all", "a", false, "Delete all Git providers") + deleteCmd.Flags().BoolVarP(&yesFlag, "yes", "y", false, "Confirm deletion without prompt") } -func removeAllGitProviders(gitProviders []apiclient.GitProvider, apiClient *apiclient.APIClient) error { +func deleteAllGitProviders(gitProviders []apiclient.GitProvider, apiClient *apiclient.APIClient) error { ctx := context.Background() for _, gitProvider := range gitProviders { - _, err := apiClient.GitProviderAPI.RemoveGitProvider(ctx, gitProvider.Id).Execute() + _, err := apiClient.GitProviderAPI.DeleteGitProvider(ctx, gitProvider.Id).Execute() if err != nil { return err } diff --git a/pkg/cmd/gitprovider/gitprovider.go b/pkg/cmd/gitprovider/gitprovider.go index e65c51a81c..1a518016db 100644 --- a/pkg/cmd/gitprovider/gitprovider.go +++ b/pkg/cmd/gitprovider/gitprovider.go @@ -9,15 +9,16 @@ import ( ) var GitProviderCmd = &cobra.Command{ - Use: "git-providers", - Aliases: []string{"git-provider", "gp"}, - Short: "Manage Git providers", + Use: "git-provider", + Short: "Manage Git provider configs", + Args: cobra.NoArgs, GroupID: util.SERVER_GROUP, + Aliases: []string{"git-providers", "gp"}, } func init() { - GitProviderCmd.AddCommand(GitProviderAddCmd) - GitProviderCmd.AddCommand(gitProviderUpdateCmd) - GitProviderCmd.AddCommand(gitProviderDeleteCmd) - GitProviderCmd.AddCommand(gitProviderListCmd) + GitProviderCmd.AddCommand(GitProviderCreateCmd) + GitProviderCmd.AddCommand(updateCmd) + GitProviderCmd.AddCommand(deleteCmd) + GitProviderCmd.AddCommand(listCmd) } diff --git a/pkg/cmd/gitprovider/list.go b/pkg/cmd/gitprovider/list.go index ecd11ff4ed..5984e09fb2 100644 --- a/pkg/cmd/gitprovider/list.go +++ b/pkg/cmd/gitprovider/list.go @@ -8,16 +8,17 @@ import ( "github.com/daytonaio/daytona/cmd/daytona/config" "github.com/daytonaio/daytona/internal/util/apiclient" + "github.com/daytonaio/daytona/pkg/cmd/common" "github.com/daytonaio/daytona/pkg/cmd/format" gitprovider_view "github.com/daytonaio/daytona/pkg/views/gitprovider" "github.com/daytonaio/daytona/pkg/views/gitprovider/list" "github.com/spf13/cobra" ) -var gitProviderListCmd = &cobra.Command{ +var listCmd = &cobra.Command{ Use: "list", - Aliases: []string{"ls"}, - Short: "Lists your registered Git providers", + Short: "Lists your registered Git provider configs", + Aliases: common.GetAliases("list"), RunE: func(cmd *cobra.Command, args []string) error { apiClient, err := apiclient.GetApiClient(nil) if err != nil { @@ -68,5 +69,5 @@ var gitProviderListCmd = &cobra.Command{ } func init() { - format.RegisterFormatFlag(gitProviderListCmd) + format.RegisterFormatFlag(listCmd) } diff --git a/pkg/cmd/gitprovider/update.go b/pkg/cmd/gitprovider/update.go index 15da83e337..99ddf2aea3 100644 --- a/pkg/cmd/gitprovider/update.go +++ b/pkg/cmd/gitprovider/update.go @@ -9,16 +9,18 @@ import ( "github.com/daytonaio/daytona/internal/util" apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" "github.com/daytonaio/daytona/pkg/apiclient" + "github.com/daytonaio/daytona/pkg/cmd/common" "github.com/daytonaio/daytona/pkg/views" gitprovider_view "github.com/daytonaio/daytona/pkg/views/gitprovider" + "github.com/daytonaio/daytona/pkg/views/selection" views_util "github.com/daytonaio/daytona/pkg/views/util" - "github.com/daytonaio/daytona/pkg/views/workspace/selection" "github.com/spf13/cobra" ) -var gitProviderUpdateCmd = &cobra.Command{ - Use: "update", - Short: "Update a Git provider", +var updateCmd = &cobra.Command{ + Use: "update", + Short: "Update a Git provider", + Aliases: common.GetAliases("update"), RunE: func(cmd *cobra.Command, args []string) error { ctx := context.Background() @@ -67,7 +69,7 @@ var gitProviderUpdateCmd = &cobra.Command{ return err } - res, err = apiClient.GitProviderAPI.SetGitProvider(ctx).GitProviderConfig(setGitProviderConfig).Execute() + res, err = apiClient.GitProviderAPI.SaveGitProvider(ctx).GitProviderConfig(setGitProviderConfig).Execute() if err != nil { return apiclient_util.HandleErrorResponse(res, err) } diff --git a/pkg/cmd/ide.go b/pkg/cmd/ide.go index 788415f1fb..884e02a278 100644 --- a/pkg/cmd/ide.go +++ b/pkg/cmd/ide.go @@ -9,6 +9,7 @@ import ( "github.com/daytonaio/daytona/cmd/daytona/config" "github.com/daytonaio/daytona/internal/jetbrains" "github.com/daytonaio/daytona/internal/util" + "github.com/daytonaio/daytona/pkg/cmd/common" ide_util "github.com/daytonaio/daytona/pkg/ide" "github.com/daytonaio/daytona/pkg/telemetry" "github.com/daytonaio/daytona/pkg/views" @@ -96,7 +97,11 @@ var ideCmd = &cobra.Command{ c.DefaultIdeId = chosenIde.Id - telemetry.AdditionalData["ide"] = chosenIde.Id + event := telemetry.NewCliEvent(telemetry.CliEventDefaultIdeSet, nil, []string{}, nil, map[string]interface{}{"ide": chosenIde.Id}) + telemetryErr := common.TrackTelemetryEvent(event, config.GetClientId()) + if telemetryErr != nil { + log.Trace(telemetryErr) + } err = c.Save() if err != nil { diff --git a/pkg/cmd/logs.go b/pkg/cmd/logs.go deleted file mode 100644 index b68113277c..0000000000 --- a/pkg/cmd/logs.go +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package cmd - -import ( - "context" - "errors" - - "github.com/daytonaio/daytona/cmd/daytona/config" - "github.com/daytonaio/daytona/internal/util" - apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" - "github.com/daytonaio/daytona/pkg/apiclient" - "github.com/daytonaio/daytona/pkg/views" - "github.com/daytonaio/daytona/pkg/views/workspace/selection" - "github.com/spf13/cobra" -) - -var followFlag bool -var workspaceFlag bool - -var logsCmd = &cobra.Command{ - Use: "logs [WORKSPACE] [PROJECT_NAME]", - Short: "View logs for a workspace/project", - Args: cobra.RangeArgs(0, 2), - GroupID: util.WORKSPACE_GROUP, - Aliases: []string{"lg", "log"}, - RunE: func(cmd *cobra.Command, args []string) error { - ctx := context.Background() - c, err := config.GetConfig() - if err != nil { - return err - } - - activeProfile, err := c.GetActiveProfile() - if err != nil { - return err - } - - var workspace *apiclient.WorkspaceDTO - apiClient, err := apiclient_util.GetApiClient(&activeProfile) - if err != nil { - return err - } - - var ( - showWorkspaceLogs = true - projectNames []string - ) - - if len(args) == 0 { - workspaceList, res, err := apiClient.WorkspaceAPI.ListWorkspaces(ctx).Execute() - if err != nil { - return apiclient_util.HandleErrorResponse(res, err) - } - if len(workspaceList) == 0 { - views.RenderInfoMessage("The workspace list is empty. Start off by running 'daytona create'.") - return nil - } - workspace = selection.GetWorkspaceFromPrompt(workspaceList, "Get Logs For") - } else { - workspace, err = apiclient_util.GetWorkspace(args[0], false) - if err != nil { - return err - } - } - - if workspace == nil { - return errors.New("workspace not found") - } else if len(workspace.Projects) == 0 { - return errors.New("no projects found in workspace") - } - - if len(args) == 2 { - projects := util.ArrayMap(workspace.Projects, func(p apiclient.Project) string { - return p.Name - }) - var found bool - for _, project := range projects { - if project == args[1] { - found = true - break - } - } - if !found { - return errors.New("project not found in workspace") - } - projectNames = append(projectNames, args[1]) - if workspaceFlag { - showWorkspaceLogs = true - } else { - showWorkspaceLogs = false - } - } else if !workspaceFlag { - projectNames = util.ArrayMap(workspace.Projects, func(p apiclient.Project) string { - return p.Name - }) - } - - apiclient_util.ReadWorkspaceLogs(ctx, activeProfile, workspace.Id, projectNames, followFlag, showWorkspaceLogs, nil) - - return nil - }, -} - -func init() { - logsCmd.Flags().BoolVarP(&followFlag, "follow", "f", false, "Follow logs") - logsCmd.Flags().BoolVarP(&workspaceFlag, "workspace", "w", false, "View workspace logs") -} diff --git a/pkg/cmd/ports/forward.go b/pkg/cmd/ports/forward.go index f911e9a791..374f6e7b26 100644 --- a/pkg/cmd/ports/forward.go +++ b/pkg/cmd/ports/forward.go @@ -9,29 +9,34 @@ import ( "errors" "fmt" "hash/fnv" + "net/http" "strconv" "time" "github.com/daytonaio/daytona/cmd/daytona/config" "github.com/daytonaio/daytona/internal/cmd/tailscale" "github.com/daytonaio/daytona/internal/util" - "github.com/daytonaio/daytona/internal/util/apiclient" + apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" + "github.com/daytonaio/daytona/pkg/apiclient" + "github.com/daytonaio/daytona/pkg/cmd/common" "github.com/daytonaio/daytona/pkg/frpc" "github.com/daytonaio/daytona/pkg/views" + "github.com/daytonaio/daytona/pkg/views/workspace/selection" log "github.com/sirupsen/logrus" qrcode "github.com/skip2/go-qrcode" "github.com/spf13/cobra" ) var publicPreview bool +var targetId string var workspaceId string -var projectName string var PortForwardCmd = &cobra.Command{ - Use: "forward [PORT] [WORKSPACE] [PROJECT]", - Short: "Forward a port from a project to your local machine", - GroupID: util.WORKSPACE_GROUP, - Args: cobra.RangeArgs(2, 3), + Use: "forward [PORT] [WORKSPACE]", + Short: "Forward a port from a workspace to your local machine", + GroupID: util.TARGET_GROUP, + Args: cobra.RangeArgs(1, 2), + Aliases: common.GetAliases("forward"), RunE: func(cmd *cobra.Command, args []string) error { c, err := config.GetConfig() if err != nil { @@ -46,22 +51,34 @@ var PortForwardCmd = &cobra.Command{ if err != nil { return err } - workspace, err := apiclient.GetWorkspace(args[1], true) + + apiClient, err := apiclient_util.GetApiClient(nil) if err != nil { return err } - workspaceId = workspace.Id + ctx := context.Background() + + var workspace *apiclient.WorkspaceDTO + var resp *http.Response - if len(args) == 3 { - projectName = args[2] + if len(args) == 2 { + workspace, resp, err = apiClient.WorkspaceAPI.FindWorkspace(ctx, args[1]).Execute() + if err != nil { + return apiclient_util.HandleErrorResponse(resp, err) + } } else { - projectName, err = apiclient.GetFirstWorkspaceProjectName(workspaceId, projectName, nil) + workspaceList, resp, err := apiClient.WorkspaceAPI.ListWorkspaces(ctx).Execute() if err != nil { - return err + return apiclient_util.HandleErrorResponse(resp, err) + } + + workspace = selection.GetWorkspaceFromPrompt(workspaceList, "Forward") + if workspace == nil { + return nil } } - hostPort, errChan := tailscale.ForwardPort(workspaceId, projectName, uint16(port), activeProfile) + hostPort, errChan := tailscale.ForwardPort(workspace.Id, uint16(port), activeProfile) if hostPort == nil { if err = <-errChan; err != nil { @@ -76,7 +93,7 @@ var PortForwardCmd = &cobra.Command{ if publicPreview { go func() { - errChan <- ForwardPublicPort(workspaceId, projectName, *hostPort, uint16(port)) + errChan <- ForwardPublicPort(targetId, workspaceId, *hostPort, uint16(port)) }() } @@ -93,21 +110,21 @@ func init() { PortForwardCmd.Flags().BoolVar(&publicPreview, "public", false, "Should be port be available publicly via an URL") } -func ForwardPublicPort(workspaceId, projectName string, hostPort, targetPort uint16) error { +func ForwardPublicPort(targetId, workspaceId string, hostPort, targetPort uint16) error { views.RenderInfoMessage("Forwarding port to a public URL...") - apiClient, err := apiclient.GetApiClient(nil) + apiClient, err := apiclient_util.GetApiClient(nil) if err != nil { return err } serverConfig, res, err := apiClient.ServerAPI.GetConfig(context.Background()).Execute() if err != nil { - return apiclient.HandleErrorResponse(res, err) + return apiclient_util.HandleErrorResponse(res, err) } h := fnv.New64() - h.Write([]byte(fmt.Sprintf("%s-%s-%s", workspaceId, projectName, serverConfig.Id))) + h.Write([]byte(fmt.Sprintf("%s-%s-%s", targetId, workspaceId, serverConfig.Id))) subDomain := fmt.Sprintf("%d-%s", targetPort, base64.RawURLEncoding.EncodeToString([]byte(fmt.Sprint(h.Sum64())))) diff --git a/pkg/cmd/prebuild/add.go b/pkg/cmd/prebuild/create.go similarity index 52% rename from pkg/cmd/prebuild/add.go rename to pkg/cmd/prebuild/create.go index 5a1bfeb080..937959a51e 100644 --- a/pkg/cmd/prebuild/add.go +++ b/pkg/cmd/prebuild/create.go @@ -13,22 +13,23 @@ import ( apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" "github.com/daytonaio/daytona/pkg/apiclient" "github.com/daytonaio/daytona/pkg/cmd/build" - "github.com/daytonaio/daytona/pkg/cmd/projectconfig" - workspace_util "github.com/daytonaio/daytona/pkg/cmd/workspace/util" + "github.com/daytonaio/daytona/pkg/cmd/common" + ws_create "github.com/daytonaio/daytona/pkg/cmd/workspace/create" + "github.com/daytonaio/daytona/pkg/cmd/workspacetemplate" "github.com/daytonaio/daytona/pkg/views" - "github.com/daytonaio/daytona/pkg/views/prebuild/add" - "github.com/daytonaio/daytona/pkg/views/workspace/selection" + "github.com/daytonaio/daytona/pkg/views/prebuild/create" + "github.com/daytonaio/daytona/pkg/views/selection" "github.com/spf13/cobra" ) -var prebuildAddCmd = &cobra.Command{ - Use: "add [PROJECT_CONFIG]", - Short: "Add a prebuild configuration", +var addCmd = &cobra.Command{ + Use: "create [WORKSPACE_CONFIG]", + Short: "Create a prebuild configuration", Args: cobra.MaximumNArgs(1), - Aliases: []string{"new", "create"}, + Aliases: common.GetAliases("create"), RunE: func(cmd *cobra.Command, args []string) error { - var prebuildAddView add.PrebuildAddView - var projectConfig *apiclient.ProjectConfig + var prebuildAddView create.PrebuildAddView + var workspaceTemplate *apiclient.WorkspaceTemplate ctx := context.Background() apiClient, err := apiclient_util.GetApiClient(nil) @@ -41,7 +42,7 @@ var prebuildAddCmd = &cobra.Command{ } if len(gitProviders) == 0 { - views.RenderInfoMessage("No registered Git providers have been found - please register a Git provider using 'daytona git-provider add' in order to start using prebuilds.") + views.RenderInfoMessage("No Git providers have been found - please create a Git provider using 'daytona git-provider create' in order to start using prebuilds.") return nil } @@ -50,32 +51,32 @@ var prebuildAddCmd = &cobra.Command{ commitIntervalFlag == 0 && triggerFilesFlag == nil { // Interactive CLI logic - projectConfigList, res, err := apiClient.ProjectConfigAPI.ListProjectConfigs(ctx).Execute() + workspaceTemplateList, res, err := apiClient.WorkspaceTemplateAPI.ListWorkspaceTemplates(ctx).Execute() if err != nil { return apiclient_util.HandleErrorResponse(res, err) } - projectConfig = selection.GetProjectConfigFromPrompt(projectConfigList, 0, false, true, "Prebuild") - if projectConfig == nil { - return errors.New("No project config selected") + workspaceTemplate = selection.GetWorkspaceTemplateFromPrompt(workspaceTemplateList, 0, false, true, "Prebuild") + if workspaceTemplate == nil { + return errors.New("No workspace template selected") } - if projectConfig.Name == selection.NewProjectConfigIdentifier { - projectConfig, err = projectconfig.RunProjectConfigAddFlow(apiClient, gitProviders, ctx) + if workspaceTemplate.Name == selection.NewWorkspaceTemplateIdentifier { + workspaceTemplate, err = workspacetemplate.RunWorkspaceTemplateAddFlow(apiClient, gitProviders, ctx) if err != nil { return err } - if projectConfig == nil { + if workspaceTemplate == nil { return nil } } - prebuildAddView.ProjectConfigName = projectConfig.Name - if projectConfig.BuildConfig == nil { - return errors.New("The chosen project config does not have a build configuration") + prebuildAddView.WorkspaceTemplateName = workspaceTemplate.Name + if workspaceTemplate.BuildConfig == nil { + return errors.New("The chosen workspace template does not have a build configuration") } - chosenBranch, err := workspace_util.GetBranchFromProjectConfig(projectConfig, apiClient, 0) + chosenBranch, err := ws_create.GetBranchFromWorkspaceTemplate(ctx, workspaceTemplate, apiClient, 0) if err != nil { return err } @@ -86,26 +87,26 @@ var prebuildAddCmd = &cobra.Command{ } prebuildAddView.RunBuildOnAdd = runFlag prebuildAddView.Branch = chosenBranch.Name - add.PrebuildCreationView(&prebuildAddView, false) + create.PrebuildCreationView(&prebuildAddView, false) } else { // Non-interactive mode: use provided arguments and flags if len(args) > 0 { - prebuildAddView.ProjectConfigName = args[0] + prebuildAddView.WorkspaceTemplateName = args[0] - // Fetch the project configuration based on the provided argument - projectConfigTemp, res, err := apiClient.ProjectConfigAPI.GetProjectConfig(ctx, prebuildAddView.ProjectConfigName).Execute() + // Fetch the workspace template based on the provided argument + workspaceTemplateTemp, res, err := apiClient.WorkspaceTemplateAPI.FindWorkspaceTemplate(ctx, prebuildAddView.WorkspaceTemplateName).Execute() if err != nil { return apiclient_util.HandleErrorResponse(res, err) } - if projectConfigTemp == nil { - return errors.New("Invalid project config specified") + if workspaceTemplateTemp == nil { + return errors.New("Invalid workspace template specified") } - prebuildAddView.ProjectConfigName = projectConfigTemp.Name - projectConfig = projectConfigTemp + prebuildAddView.WorkspaceTemplateName = workspaceTemplateTemp.Name + workspaceTemplate = workspaceTemplateTemp } else { - return errors.New("Project config must be specified when using flags") + return errors.New("Workspace template must be specified when using flags") } // Validate and handle required flags @@ -157,7 +158,7 @@ var prebuildAddCmd = &cobra.Command{ newPrebuild.TriggerFiles = prebuildAddView.TriggerFiles } - prebuildId, res, err := apiClient.PrebuildAPI.SetPrebuild(ctx, prebuildAddView.ProjectConfigName).Prebuild(newPrebuild).Execute() + prebuildId, res, err := apiClient.PrebuildAPI.SavePrebuild(ctx, prebuildAddView.WorkspaceTemplateName).Prebuild(newPrebuild).Execute() if err != nil { return apiclient_util.HandleErrorResponse(res, err) } @@ -165,7 +166,7 @@ var prebuildAddCmd = &cobra.Command{ views.RenderInfoMessage("Prebuild added successfully") if prebuildAddView.RunBuildOnAdd { - buildId, err := build.CreateBuild(apiClient, projectConfig, prebuildAddView.Branch, &prebuildId) + buildId, err := build.CreateBuild(apiClient, workspaceTemplate, prebuildAddView.Branch, &prebuildId) if err != nil { return err } @@ -178,9 +179,9 @@ var prebuildAddCmd = &cobra.Command{ } func init() { - prebuildAddCmd.Flags().BoolVar(&runFlag, "run", false, "Run the prebuild once after adding it") - prebuildAddCmd.Flags().StringVarP(&branchFlag, "branch", "b", "", "Git branch for the prebuild") - prebuildAddCmd.Flags().IntVarP(&retentionFlag, "retention", "r", 0, "Maximum number of resulting builds stored at a time") - prebuildAddCmd.Flags().IntVarP(&commitIntervalFlag, "commit-interval", "c", 0, "Commit interval for running a prebuild - leave blank to ignore push events") - prebuildAddCmd.Flags().StringSliceVarP(&triggerFilesFlag, "trigger-files", "t", nil, "Full paths of files whose changes should explicitly trigger a prebuild") + addCmd.Flags().BoolVar(&runFlag, "run", false, "Run the prebuild once after adding it") + addCmd.Flags().StringVarP(&branchFlag, "branch", "b", "", "Git branch for the prebuild") + addCmd.Flags().IntVarP(&retentionFlag, "retention", "r", 0, "Maximum number of resulting builds stored at a time") + addCmd.Flags().IntVarP(&commitIntervalFlag, "commit-interval", "c", 0, "Commit interval for running a prebuild - leave blank to ignore push events") + addCmd.Flags().StringSliceVarP(&triggerFilesFlag, "trigger-files", "t", nil, "Full paths of files whose changes should explicitly trigger a prebuild") } diff --git a/pkg/cmd/prebuild/delete.go b/pkg/cmd/prebuild/delete.go index 1c900b577d..270d2b022b 100644 --- a/pkg/cmd/prebuild/delete.go +++ b/pkg/cmd/prebuild/delete.go @@ -9,23 +9,24 @@ import ( apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" "github.com/daytonaio/daytona/pkg/apiclient" + "github.com/daytonaio/daytona/pkg/cmd/common" "github.com/daytonaio/daytona/pkg/views" + "github.com/daytonaio/daytona/pkg/views/selection" views_util "github.com/daytonaio/daytona/pkg/views/util" - "github.com/daytonaio/daytona/pkg/views/workspace/selection" "github.com/spf13/cobra" ) var forceFlag bool -var prebuildDeleteCmd = &cobra.Command{ - Use: "delete [PROJECT_CONFIG] [PREBUILD]", +var deleteCmd = &cobra.Command{ + Use: "delete [WORKSPACE_CONFIG] [PREBUILD]", Short: "Delete a prebuild configuration", - Aliases: []string{"remove", "rm"}, Args: cobra.MaximumNArgs(2), + Aliases: common.GetAliases("delete"), RunE: func(cmd *cobra.Command, args []string) error { var selectedPrebuild *apiclient.PrebuildDTO var selectedPrebuildId string - var selectedProjectConfigName string + var selectedWorkspaceTemplateName string apiClient, err := apiclient_util.GetApiClient(nil) if err != nil { @@ -37,8 +38,8 @@ var prebuildDeleteCmd = &cobra.Command{ var res *http.Response if len(args) == 1 { - selectedProjectConfigName = args[0] - prebuilds, res, err = apiClient.PrebuildAPI.ListPrebuildsForProjectConfig(context.Background(), selectedProjectConfigName).Execute() + selectedWorkspaceTemplateName = args[0] + prebuilds, res, err = apiClient.PrebuildAPI.ListPrebuildsForWorkspaceTemplate(context.Background(), selectedWorkspaceTemplateName).Execute() if err != nil { return apiclient_util.HandleErrorResponse(res, err) } @@ -59,13 +60,13 @@ var prebuildDeleteCmd = &cobra.Command{ return nil } selectedPrebuildId = selectedPrebuild.Id - selectedProjectConfigName = selectedPrebuild.ProjectConfigName + selectedWorkspaceTemplateName = selectedPrebuild.WorkspaceTemplateName } else { - selectedProjectConfigName = args[0] + selectedWorkspaceTemplateName = args[0] selectedPrebuildId = args[1] } - res, err := apiClient.PrebuildAPI.DeletePrebuild(context.Background(), selectedProjectConfigName, selectedPrebuildId).Force(forceFlag).Execute() + res, err := apiClient.PrebuildAPI.DeletePrebuild(context.Background(), selectedWorkspaceTemplateName, selectedPrebuildId).Force(forceFlag).Execute() if err != nil { return apiclient_util.HandleErrorResponse(res, err) } @@ -77,5 +78,5 @@ var prebuildDeleteCmd = &cobra.Command{ } func init() { - prebuildDeleteCmd.Flags().BoolVarP(&forceFlag, "force", "f", false, "Force delete prebuild") + deleteCmd.Flags().BoolVarP(&forceFlag, "force", "f", false, "Force delete prebuild") } diff --git a/pkg/cmd/prebuild/info.go b/pkg/cmd/prebuild/info.go index ffaad2a3fb..d7b368718d 100644 --- a/pkg/cmd/prebuild/info.go +++ b/pkg/cmd/prebuild/info.go @@ -9,17 +9,19 @@ import ( apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" "github.com/daytonaio/daytona/pkg/apiclient" + "github.com/daytonaio/daytona/pkg/cmd/common" "github.com/daytonaio/daytona/pkg/cmd/format" "github.com/daytonaio/daytona/pkg/views/prebuild/info" + "github.com/daytonaio/daytona/pkg/views/selection" views_util "github.com/daytonaio/daytona/pkg/views/util" - "github.com/daytonaio/daytona/pkg/views/workspace/selection" "github.com/spf13/cobra" ) -var prebuildInfoCmd = &cobra.Command{ - Use: "info", - Short: "Show prebuild configuration info", - Args: cobra.MaximumNArgs(2), +var infoCmd = &cobra.Command{ + Use: "info", + Short: "Show prebuild configuration info", + Args: cobra.MaximumNArgs(2), + Aliases: common.GetAliases("info"), RunE: func(cmd *cobra.Command, args []string) error { var prebuild *apiclient.PrebuildDTO var res *http.Response @@ -33,11 +35,11 @@ var prebuildInfoCmd = &cobra.Command{ if len(args) < 2 { var prebuilds []apiclient.PrebuildDTO - var selectedProjectConfigName string + var selectedWorkspaceTemplateName string if len(args) == 1 { - selectedProjectConfigName = args[0] - prebuilds, res, err = apiClient.PrebuildAPI.ListPrebuildsForProjectConfig(context.Background(), selectedProjectConfigName).Execute() + selectedWorkspaceTemplateName = args[0] + prebuilds, res, err = apiClient.PrebuildAPI.ListPrebuildsForWorkspaceTemplate(context.Background(), selectedWorkspaceTemplateName).Execute() if err != nil { return apiclient_util.HandleErrorResponse(res, err) } @@ -66,7 +68,7 @@ var prebuildInfoCmd = &cobra.Command{ return nil } } else { - prebuild, res, err = apiClient.PrebuildAPI.GetPrebuild(ctx, args[0], args[1]).Execute() + prebuild, res, err = apiClient.PrebuildAPI.FindPrebuild(ctx, args[0], args[1]).Execute() if err != nil { return apiclient_util.HandleErrorResponse(res, err) } @@ -84,5 +86,5 @@ var prebuildInfoCmd = &cobra.Command{ } func init() { - format.RegisterFormatFlag(prebuildInfoCmd) + format.RegisterFormatFlag(infoCmd) } diff --git a/pkg/cmd/prebuild/list.go b/pkg/cmd/prebuild/list.go index 0b43243980..8e66d6b0a0 100644 --- a/pkg/cmd/prebuild/list.go +++ b/pkg/cmd/prebuild/list.go @@ -7,16 +7,17 @@ import ( "context" apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" + "github.com/daytonaio/daytona/pkg/cmd/common" "github.com/daytonaio/daytona/pkg/cmd/format" view "github.com/daytonaio/daytona/pkg/views/prebuild/list" "github.com/spf13/cobra" ) -var prebuildListCmd = &cobra.Command{ +var listCmd = &cobra.Command{ Use: "list", Short: "List prebuild configurations", - Aliases: []string{"ls"}, Args: cobra.NoArgs, + Aliases: common.GetAliases("list"), RunE: func(cmd *cobra.Command, args []string) error { ctx := context.Background() @@ -42,5 +43,5 @@ var prebuildListCmd = &cobra.Command{ } func init() { - format.RegisterFormatFlag(prebuildListCmd) + format.RegisterFormatFlag(listCmd) } diff --git a/pkg/cmd/prebuild/prebuild.go b/pkg/cmd/prebuild/prebuild.go index 63e2d11421..53b2dfbd20 100644 --- a/pkg/cmd/prebuild/prebuild.go +++ b/pkg/cmd/prebuild/prebuild.go @@ -10,15 +10,16 @@ import ( var PrebuildCmd = &cobra.Command{ Use: "prebuild", - Aliases: []string{"pb", "prebuilds"}, Short: "Manage prebuilds", - GroupID: util.WORKSPACE_GROUP, + Args: cobra.NoArgs, + GroupID: util.TARGET_GROUP, + Aliases: []string{"prebuilds", "pb"}, } func init() { - PrebuildCmd.AddCommand(prebuildAddCmd) - PrebuildCmd.AddCommand(prebuildListCmd) - PrebuildCmd.AddCommand(prebuildInfoCmd) - PrebuildCmd.AddCommand(prebuildUpdateCmd) - PrebuildCmd.AddCommand(prebuildDeleteCmd) + PrebuildCmd.AddCommand(addCmd) + PrebuildCmd.AddCommand(listCmd) + PrebuildCmd.AddCommand(infoCmd) + PrebuildCmd.AddCommand(updateCmd) + PrebuildCmd.AddCommand(deleteCmd) } diff --git a/pkg/cmd/prebuild/update.go b/pkg/cmd/prebuild/update.go index 047e0de620..4642f16b87 100644 --- a/pkg/cmd/prebuild/update.go +++ b/pkg/cmd/prebuild/update.go @@ -12,21 +12,23 @@ import ( apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" "github.com/daytonaio/daytona/pkg/apiclient" "github.com/daytonaio/daytona/pkg/cmd/build" + "github.com/daytonaio/daytona/pkg/cmd/common" "github.com/daytonaio/daytona/pkg/views" - "github.com/daytonaio/daytona/pkg/views/prebuild/add" + "github.com/daytonaio/daytona/pkg/views/prebuild/create" + "github.com/daytonaio/daytona/pkg/views/selection" views_util "github.com/daytonaio/daytona/pkg/views/util" - "github.com/daytonaio/daytona/pkg/views/workspace/selection" "github.com/spf13/cobra" ) -var prebuildUpdateCmd = &cobra.Command{ - Use: "update [PROJECT_CONFIG] [PREBUILD_ID]", - Short: "Update a prebuild configuration", - Args: cobra.MaximumNArgs(2), +var updateCmd = &cobra.Command{ + Use: "update [WORKSPACE_CONFIG] [PREBUILD_ID]", + Short: "Update a prebuild configuration", + Args: cobra.MaximumNArgs(2), + Aliases: common.GetAliases("update"), RunE: func(cmd *cobra.Command, args []string) error { - var prebuildAddView add.PrebuildAddView + var prebuildAddView create.PrebuildAddView var prebuild *apiclient.PrebuildDTO - var projectConfigRecieved string + var workspaceTemplateRecieved string var retention int ctx := context.Background() @@ -42,7 +44,7 @@ var prebuildUpdateCmd = &cobra.Command{ } if len(userGitProviders) == 0 { - views.RenderInfoMessage("No registered Git providers have been found - please register a Git provider using 'daytona git-provider add' in order to start using prebuilds.") + views.RenderInfoMessage("No registered Git providers have been found - please register a Git provider using 'daytona git-provider create' in order to start using prebuilds.") return nil } @@ -50,13 +52,13 @@ var prebuildUpdateCmd = &cobra.Command{ if len(args) == 2 || (branchFlag != "" || retentionFlag != 0 || commitIntervalFlag != 0 || len(triggerFilesFlag) > 0) { // Non-interactive mode: use provided arguments and flags if len(args) < 2 { - return errors.New("Both project config name and prebuild ID must be specified when using flags") + return errors.New("Both workspace template name and prebuild ID must be specified when using flags") } - projectConfigRecieved = args[0] + workspaceTemplateRecieved = args[0] prebuildID := args[1] - prebuild, res, err = apiClient.PrebuildAPI.GetPrebuild(ctx, projectConfigRecieved, prebuildID).Execute() + prebuild, res, err = apiClient.PrebuildAPI.FindPrebuild(ctx, workspaceTemplateRecieved, prebuildID).Execute() if err != nil { return apiclient_util.HandleErrorResponse(res, err) } @@ -79,18 +81,18 @@ var prebuildUpdateCmd = &cobra.Command{ } prebuildAddView.Branch = prebuild.Branch prebuildAddView.Retention = strconv.Itoa(int(prebuild.Retention)) - prebuildAddView.ProjectConfigName = projectConfigRecieved + prebuildAddView.WorkspaceTemplateName = workspaceTemplateRecieved prebuildAddView.TriggerFiles = prebuild.TriggerFiles prebuildAddView.CommitInterval = strconv.Itoa(int(*prebuild.CommitInterval)) retention = int(prebuild.Retention) } else { // Interactive mode: Prompt for details var prebuilds []apiclient.PrebuildDTO - var selectedProjectConfigName string + var selectedWorkspaceTemplateName string if len(args) == 1 { - selectedProjectConfigName = args[0] - prebuilds, res, err = apiClient.PrebuildAPI.ListPrebuildsForProjectConfig(ctx, selectedProjectConfigName).Execute() + selectedWorkspaceTemplateName = args[0] + prebuilds, res, err = apiClient.PrebuildAPI.ListPrebuildsForWorkspaceTemplate(ctx, selectedWorkspaceTemplateName).Execute() if err != nil { return apiclient_util.HandleErrorResponse(res, err) } @@ -111,11 +113,11 @@ var prebuildUpdateCmd = &cobra.Command{ return nil } - projectConfigRecieved = prebuild.ProjectConfigName - prebuildAddView = add.PrebuildAddView{ - Branch: prebuild.Branch, - Retention: strconv.Itoa(int(prebuild.Retention)), - ProjectConfigName: projectConfigRecieved, + workspaceTemplateRecieved = prebuild.WorkspaceTemplateName + prebuildAddView = create.PrebuildAddView{ + Branch: prebuild.Branch, + Retention: strconv.Itoa(int(prebuild.Retention)), + WorkspaceTemplateName: workspaceTemplateRecieved, } retention, err = strconv.Atoi(prebuildAddView.Retention) if err != nil { @@ -128,7 +130,7 @@ var prebuildUpdateCmd = &cobra.Command{ if len(prebuild.TriggerFiles) > 0 { prebuildAddView.TriggerFiles = prebuild.TriggerFiles } - add.PrebuildCreationView(&prebuildAddView, false) + create.PrebuildCreationView(&prebuildAddView, false) } prebuildAddView.RunBuildOnAdd = runFlag @@ -155,7 +157,7 @@ var prebuildUpdateCmd = &cobra.Command{ newPrebuild.TriggerFiles = prebuildAddView.TriggerFiles } - prebuildId, res, err := apiClient.PrebuildAPI.SetPrebuild(ctx, prebuildAddView.ProjectConfigName).Prebuild(newPrebuild).Execute() + prebuildId, res, err := apiClient.PrebuildAPI.SavePrebuild(ctx, prebuildAddView.WorkspaceTemplateName).Prebuild(newPrebuild).Execute() if err != nil { return apiclient_util.HandleErrorResponse(res, err) } @@ -163,12 +165,12 @@ var prebuildUpdateCmd = &cobra.Command{ views.RenderInfoMessage("Prebuild updated successfully") if prebuildAddView.RunBuildOnAdd { - projectConfig, res, err := apiClient.ProjectConfigAPI.GetProjectConfig(ctx, prebuildAddView.ProjectConfigName).Execute() + workspaceTemplate, res, err := apiClient.WorkspaceTemplateAPI.FindWorkspaceTemplate(ctx, prebuildAddView.WorkspaceTemplateName).Execute() if err != nil { return apiclient_util.HandleErrorResponse(res, err) } - buildId, err := build.CreateBuild(apiClient, projectConfig, *newPrebuild.Branch, &prebuildId) + buildId, err := build.CreateBuild(apiClient, workspaceTemplate, *newPrebuild.Branch, &prebuildId) if err != nil { return err } @@ -189,9 +191,9 @@ var ( ) func init() { - prebuildUpdateCmd.Flags().StringVarP(&branchFlag, "branch", "b", "", "Git branch for the prebuild") - prebuildUpdateCmd.Flags().IntVarP(&retentionFlag, "retention", "r", 0, "Maximum number of resulting builds stored at a time") - prebuildUpdateCmd.Flags().IntVarP(&commitIntervalFlag, "commit-interval", "c", 0, "Commit interval for running a prebuild - leave blank to ignore push events") - prebuildUpdateCmd.Flags().StringSliceVarP(&triggerFilesFlag, "trigger-files", "t", nil, "Full paths of files whose changes should explicitly trigger a prebuild") - prebuildUpdateCmd.Flags().BoolVar(&runFlag, "run", false, "Run the prebuild once after updating it") + updateCmd.Flags().StringVarP(&branchFlag, "branch", "b", "", "Git branch for the prebuild") + updateCmd.Flags().IntVarP(&retentionFlag, "retention", "r", 0, "Maximum number of resulting builds stored at a time") + updateCmd.Flags().IntVarP(&commitIntervalFlag, "commit-interval", "c", 0, "Commit interval for running a prebuild - leave blank to ignore push events") + updateCmd.Flags().StringSliceVarP(&triggerFilesFlag, "trigger-files", "t", nil, "Full paths of files whose changes should explicitly trigger a prebuild") + updateCmd.Flags().BoolVar(&runFlag, "run", false, "Run the prebuild once after updating it") } diff --git a/pkg/cmd/profile/add.go b/pkg/cmd/profile/create.go similarity index 94% rename from pkg/cmd/profile/add.go rename to pkg/cmd/profile/create.go index 83c2ae5300..a5c3eb85be 100644 --- a/pkg/cmd/profile/add.go +++ b/pkg/cmd/profile/create.go @@ -6,16 +6,17 @@ package profile import ( "github.com/daytonaio/daytona/cmd/daytona/config" "github.com/daytonaio/daytona/internal/util" + "github.com/daytonaio/daytona/pkg/cmd/common" "github.com/daytonaio/daytona/pkg/views/profile" "github.com/spf13/cobra" ) var ProfileAddCmd = &cobra.Command{ - Use: "add", - Short: "Add profile", + Use: "create", + Short: "Create a profile", Args: cobra.NoArgs, - Aliases: []string{"new"}, + Aliases: common.GetAliases("create"), RunE: func(cmd *cobra.Command, args []string) error { c, err := config.GetConfig() if err != nil { diff --git a/pkg/cmd/profile/delete.go b/pkg/cmd/profile/delete.go index c623b13056..252039b6ec 100644 --- a/pkg/cmd/profile/delete.go +++ b/pkg/cmd/profile/delete.go @@ -7,17 +7,18 @@ import ( "errors" "github.com/daytonaio/daytona/cmd/daytona/config" + "github.com/daytonaio/daytona/pkg/cmd/common" "github.com/daytonaio/daytona/pkg/views/profile" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) -var profileDeleteCmd = &cobra.Command{ - Use: "delete", - Short: "Delete profile [PROFILE_NAME]", +var deleteCmd = &cobra.Command{ + Use: "delete [PROFILE_NAME]", + Short: "Delete a profile", Args: cobra.RangeArgs(0, 1), - Aliases: []string{"remove", "rm"}, + Aliases: common.GetAliases("delete"), RunE: func(cmd *cobra.Command, args []string) error { c, err := config.GetConfig() if err != nil { diff --git a/pkg/cmd/profile/list.go b/pkg/cmd/profile/list.go index fd41ca6850..6498fb87e9 100644 --- a/pkg/cmd/profile/list.go +++ b/pkg/cmd/profile/list.go @@ -7,16 +7,17 @@ import ( "fmt" "github.com/daytonaio/daytona/cmd/daytona/config" + "github.com/daytonaio/daytona/pkg/cmd/common" "github.com/daytonaio/daytona/pkg/cmd/format" "github.com/daytonaio/daytona/pkg/views/profile" "github.com/spf13/cobra" ) -var profileListCmd = &cobra.Command{ +var listCmd = &cobra.Command{ Use: "list", Short: "List profiles", - Aliases: []string{"ls"}, + Aliases: common.GetAliases("list"), RunE: func(cmd *cobra.Command, args []string) error { c, err := config.GetConfig() if err != nil { @@ -44,5 +45,5 @@ var profileListCmd = &cobra.Command{ } func init() { - format.RegisterFormatFlag(profileListCmd) + format.RegisterFormatFlag(listCmd) } diff --git a/pkg/cmd/profile/profile.go b/pkg/cmd/profile/profile.go index 85fe58a491..1f1ce2623b 100644 --- a/pkg/cmd/profile/profile.go +++ b/pkg/cmd/profile/profile.go @@ -11,14 +11,16 @@ import ( var ProfileCmd = &cobra.Command{ Use: "profile", Short: "Manage profiles", + Args: cobra.NoArgs, GroupID: util.PROFILE_GROUP, + Aliases: []string{"profiles"}, } func init() { ProfileCmd.AddGroup(&cobra.Group{ID: util.PROFILE_GROUP, Title: "Profile"}) - ProfileCmd.AddCommand(profileListCmd) + ProfileCmd.AddCommand(listCmd) ProfileCmd.AddCommand(ProfileUseCmd) ProfileCmd.AddCommand(ProfileAddCmd) - ProfileCmd.AddCommand(profileEditCmd) - ProfileCmd.AddCommand(profileDeleteCmd) + ProfileCmd.AddCommand(updateCmd) + ProfileCmd.AddCommand(deleteCmd) } diff --git a/pkg/cmd/profile/edit.go b/pkg/cmd/profile/update.go similarity index 84% rename from pkg/cmd/profile/edit.go rename to pkg/cmd/profile/update.go index a68b03353f..4902324fda 100644 --- a/pkg/cmd/profile/edit.go +++ b/pkg/cmd/profile/update.go @@ -7,15 +7,17 @@ import ( "errors" "github.com/daytonaio/daytona/cmd/daytona/config" + "github.com/daytonaio/daytona/pkg/cmd/common" "github.com/daytonaio/daytona/pkg/views/profile" "github.com/spf13/cobra" ) -var profileEditCmd = &cobra.Command{ - Use: "edit", - Short: "Edit profile [PROFILE_NAME]", - Args: cobra.RangeArgs(0, 1), +var updateCmd = &cobra.Command{ + Use: "update", + Short: "Update profile [PROFILE_NAME]", + Args: cobra.RangeArgs(0, 1), + Aliases: common.GetAliases("update"), RunE: func(cmd *cobra.Command, args []string) error { c, err := config.GetConfig() if err != nil { @@ -111,7 +113,7 @@ func editProfile(profileToEdit *config.Profile, profileView profile.ProfileAddVi } func init() { - profileEditCmd.Flags().StringVarP(&profileNameFlag, "name", "n", "", "Profile name") - profileEditCmd.Flags().StringVarP(&apiUrlFlag, "api-url", "a", "", "API URL") - profileEditCmd.Flags().StringVarP(&apiKeyFlag, "api-key", "k", "", "API Key") + updateCmd.Flags().StringVarP(&profileNameFlag, "name", "n", "", "Profile name") + updateCmd.Flags().StringVarP(&apiUrlFlag, "api-url", "a", "", "API URL") + updateCmd.Flags().StringVarP(&apiKeyFlag, "api-key", "k", "", "API Key") } diff --git a/pkg/cmd/profile/use.go b/pkg/cmd/profile/use.go index 6ab6d78f5f..fd2a7dacf3 100644 --- a/pkg/cmd/profile/use.go +++ b/pkg/cmd/profile/use.go @@ -29,12 +29,12 @@ var ProfileUseCmd = &cobra.Command{ profilesList := c.Profiles if len(profilesList) == 0 { - views.RenderInfoMessage("Add a profile by running `daytona profile add`") + views.RenderInfoMessage("Create a profile by running `daytona profile create`") return nil } if len(profilesList) == 1 { - views.RenderInfoMessage(fmt.Sprintf("You are using profile %s. Add a new profile by running `daytona profile add`", profilesList[0].Name)) + views.RenderInfoMessage(fmt.Sprintf("You are using profile %s. Add a new profile by running `daytona profile create`", profilesList[0].Name)) return nil } diff --git a/pkg/cmd/profiledata/env/list.go b/pkg/cmd/profiledata/env/list.go deleted file mode 100644 index 644124d102..0000000000 --- a/pkg/cmd/profiledata/env/list.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package env - -import ( - "context" - - "github.com/daytonaio/daytona/internal/util/apiclient" - "github.com/daytonaio/daytona/pkg/cmd/format" - "github.com/daytonaio/daytona/pkg/views/env" - "github.com/spf13/cobra" -) - -var listCmd = &cobra.Command{ - Use: "list", - Short: "List profile environment variables", - Aliases: []string{"ls"}, - RunE: func(cmd *cobra.Command, args []string) error { - apiClient, err := apiclient.GetApiClient(nil) - if err != nil { - return err - } - ctx := context.Background() - - profileData, res, err := apiClient.ProfileAPI.GetProfileData(ctx).Execute() - if err != nil { - return apiclient.HandleErrorResponse(res, err) - } - - if format.FormatFlag != "" { - if profileData.EnvVars == nil { - profileData.EnvVars = map[string]string{} - } - formattedData := format.NewFormatter(profileData.EnvVars) - formattedData.Print() - return nil - } - - env.List(profileData.EnvVars) - return nil - }, -} - -func init() { - format.RegisterFormatFlag(listCmd) -} diff --git a/pkg/cmd/profiledata/env/set.go b/pkg/cmd/profiledata/env/set.go deleted file mode 100644 index d05b8bb12a..0000000000 --- a/pkg/cmd/profiledata/env/set.go +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package env - -import ( - "context" - "fmt" - "strings" - - "github.com/charmbracelet/huh" - "github.com/daytonaio/daytona/internal/util/apiclient" - "github.com/daytonaio/daytona/pkg/views" - "github.com/spf13/cobra" -) - -var setCmd = &cobra.Command{ - Use: "set [KEY=VALUE]...", - Short: "Set profile environment variables", - Aliases: []string{"s", "update", "add", "delete", "rm"}, - RunE: func(cmd *cobra.Command, args []string) error { - apiClient, err := apiclient.GetApiClient(nil) - if err != nil { - return err - } - ctx := context.Background() - - profileData, res, err := apiClient.ProfileAPI.GetProfileData(ctx).Execute() - if err != nil { - return apiclient.HandleErrorResponse(res, err) - } - - if profileData.EnvVars == nil { - profileData.EnvVars = map[string]string{} - } - - if len(args) > 0 { - for _, arg := range args { - kv := strings.Split(arg, "=") - if len(kv) != 2 { - return fmt.Errorf("invalid key-value pair: %s", arg) - } - (profileData.EnvVars)[kv[0]] = kv[1] - } - } else { - form := huh.NewForm( - huh.NewGroup( - views.GetEnvVarsInput(&profileData.EnvVars), - ), - ).WithTheme(views.GetCustomTheme()).WithHeight(12) - - err = form.Run() - if err != nil { - return err - } - } - - res, err = apiClient.ProfileAPI.SetProfileData(ctx).ProfileData(*profileData).Execute() - if err != nil { - return apiclient.HandleErrorResponse(res, err) - } - - views.RenderInfoMessageBold("Profile environment variables have been successfully set") - return nil - }, -} diff --git a/pkg/cmd/projectconfig/add.go b/pkg/cmd/projectconfig/add.go deleted file mode 100644 index ce1d3d003d..0000000000 --- a/pkg/cmd/projectconfig/add.go +++ /dev/null @@ -1,294 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package projectconfig - -import ( - "context" - "errors" - "fmt" - "net/url" - - "github.com/daytonaio/daytona/internal/util" - apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" - "github.com/daytonaio/daytona/pkg/apiclient" - workspace_util "github.com/daytonaio/daytona/pkg/cmd/workspace/util" - "github.com/daytonaio/daytona/pkg/common" - "github.com/daytonaio/daytona/pkg/views" - views_util "github.com/daytonaio/daytona/pkg/views/util" - "github.com/daytonaio/daytona/pkg/views/workspace/create" - "github.com/spf13/cobra" -) - -var projectConfigAddCmd = &cobra.Command{ - Use: "add", - Aliases: []string{"new", "create"}, - Short: "Add a project config", - Args: cobra.MaximumNArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { - var projectConfig *apiclient.ProjectConfig - var projectConfigName *string - ctx := context.Background() - - apiClient, err := apiclient_util.GetApiClient(nil) - if err != nil { - return err - } - - gitProviders, res, err := apiClient.GitProviderAPI.ListGitProviders(ctx).Execute() - if err != nil { - return apiclient_util.HandleErrorResponse(res, err) - } - - if len(args) == 0 { - projectConfig, err = RunProjectConfigAddFlow(apiClient, gitProviders, ctx) - if err != nil { - return err - } - if projectConfig == nil { - return nil - } - projectConfigName = &projectConfig.Name - } else { - projectConfigName, err = processCmdArgument(args[0], apiClient, ctx) - if err != nil { - return err - } - } - - if projectConfigName == nil { - return errors.New("project config name is required") - } - - views.RenderInfoMessage(fmt.Sprintf("Project config %s added successfully", *projectConfigName)) - return nil - }, -} - -func RunProjectConfigAddFlow(apiClient *apiclient.APIClient, gitProviders []apiclient.GitProvider, ctx context.Context) (*apiclient.ProjectConfig, error) { - if workspace_util.CheckAnyProjectConfigurationFlagSet(projectConfigurationFlags) { - return nil, errors.New("please provide the repository URL in order to set up custom project config details through the CLI") - } - - var createDtos []apiclient.CreateProjectDTO - existingProjectConfigNames, err := GetExistingProjectConfigNames(apiClient) - if err != nil { - return nil, err - } - - apiServerConfig, res, err := apiClient.ServerAPI.GetConfig(context.Background()).Execute() - if err != nil { - return nil, apiclient_util.HandleErrorResponse(res, err) - } - - projectDefaults := &views_util.ProjectConfigDefaults{ - BuildChoice: views_util.AUTOMATIC, - Image: &apiServerConfig.DefaultProjectImage, - ImageUser: &apiServerConfig.DefaultProjectUser, - DevcontainerFilePath: create.DEVCONTAINER_FILEPATH, - } - - createDtos, err = workspace_util.GetProjectsCreationDataFromPrompt(workspace_util.ProjectsDataPromptConfig{ - UserGitProviders: gitProviders, - Manual: *projectConfigurationFlags.Manual, - MultiProject: false, - SkipBranchSelection: true, - ApiClient: apiClient, - Defaults: projectDefaults, - }) - - if err != nil { - if common.IsCtrlCAbort(err) { - return nil, nil - } else { - return nil, err - } - } - - create.ProjectsConfigurationChanged, err = create.RunProjectConfiguration(&createDtos, *projectDefaults, false) - if err != nil { - return nil, err - } - - if len(createDtos) == 0 { - return nil, errors.New("no projects found") - } - - if createDtos[0].Name == "" { - return nil, errors.New("project config name is required") - } - - initialSuggestion := createDtos[0].Name - - chosenName := workspace_util.GetSuggestedName(initialSuggestion, existingProjectConfigNames) - - submissionFormConfig := create.SubmissionFormConfig{ - ChosenName: &chosenName, - SuggestedName: chosenName, - ExistingNames: existingProjectConfigNames, - ProjectList: &createDtos, - NameLabel: "Project config", - Defaults: projectDefaults, - } - - pcFlag := false - err = create.RunSubmissionForm(submissionFormConfig, &pcFlag) - if err != nil { - return nil, err - } - - createProjectConfig := apiclient.CreateProjectConfigDTO{ - Name: chosenName, - BuildConfig: createDtos[0].BuildConfig, - Image: createDtos[0].Image, - User: createDtos[0].User, - RepositoryUrl: createDtos[0].Source.Repository.Url, - EnvVars: createDtos[0].EnvVars, - GitProviderConfigId: createDtos[0].GitProviderConfigId, - } - - res, err = apiClient.ProjectConfigAPI.SetProjectConfig(ctx).ProjectConfig(createProjectConfig).Execute() - if err != nil { - return nil, apiclient_util.HandleErrorResponse(res, err) - } - - projectConfig := apiclient.ProjectConfig{ - BuildConfig: createProjectConfig.BuildConfig, - Default: false, - EnvVars: createProjectConfig.EnvVars, - Name: createProjectConfig.Name, - Prebuilds: nil, - RepositoryUrl: createProjectConfig.RepositoryUrl, - GitProviderConfigId: createProjectConfig.GitProviderConfigId, - } - - if createProjectConfig.Image != nil { - projectConfig.Image = *createProjectConfig.Image - } - - if createProjectConfig.User != nil { - projectConfig.User = *createProjectConfig.User - } - - if createProjectConfig.GitProviderConfigId == nil && *createProjectConfig.GitProviderConfigId == "" { - gitProviderConfigId, res, err := apiClient.GitProviderAPI.GetGitProviderIdForUrl(ctx, url.QueryEscape(createProjectConfig.RepositoryUrl)).Execute() - if err != nil { - return nil, apiclient_util.HandleErrorResponse(res, err) - } - projectConfig.GitProviderConfigId = &gitProviderConfigId - } - - return &projectConfig, nil -} - -func processCmdArgument(argument string, apiClient *apiclient.APIClient, ctx context.Context) (*string, error) { - if *projectConfigurationFlags.Builder != "" && *projectConfigurationFlags.Builder != views_util.DEVCONTAINER && *projectConfigurationFlags.DevcontainerPath != "" { - return nil, fmt.Errorf("can't set devcontainer file path if builder is not set to %s", views_util.DEVCONTAINER) - } - - apiServerConfig, res, err := apiClient.ServerAPI.GetConfig(context.Background()).Execute() - if err != nil { - return nil, apiclient_util.HandleErrorResponse(res, err) - } - - existingProjectConfigNames, err := GetExistingProjectConfigNames(apiClient) - if err != nil { - return nil, err - } - - repoUrl, err := util.GetValidatedUrl(argument) - if err != nil { - return nil, err - } - - _, res, err = apiClient.GitProviderAPI.GetGitContext(ctx).Repository(apiclient.GetRepositoryContext{ - Url: repoUrl, - }).Execute() - if err != nil { - return nil, apiclient_util.HandleErrorResponse(res, err) - } - - projectConfigurationFlags.GitProviderConfig, err = workspace_util.GetGitProviderConfigIdFromFlag(ctx, apiClient, projectConfigurationFlags.GitProviderConfig) - if err != nil { - return nil, err - } - - project, err := workspace_util.GetCreateProjectDtoFromFlags(projectConfigurationFlags) - if err != nil { - return nil, err - } - - var name string - if nameFlag != "" { - name = nameFlag - } else { - projectName := workspace_util.GetProjectNameFromRepo(repoUrl) - name = workspace_util.GetSuggestedName(projectName, existingProjectConfigNames) - } - - if project.GitProviderConfigId == nil || *project.GitProviderConfigId == "" { - gitProviderConfigId, res, err := apiClient.GitProviderAPI.GetGitProviderIdForUrl(ctx, url.QueryEscape(repoUrl)).Execute() - if err != nil { - return nil, apiclient_util.HandleErrorResponse(res, err) - } - *project.GitProviderConfigId = gitProviderConfigId - } - - newProjectConfig := apiclient.CreateProjectConfigDTO{ - Name: name, - BuildConfig: project.BuildConfig, - Image: project.Image, - User: project.User, - RepositoryUrl: repoUrl, - EnvVars: project.EnvVars, - GitProviderConfigId: project.GitProviderConfigId, - } - - if newProjectConfig.Image == nil { - newProjectConfig.Image = &apiServerConfig.DefaultProjectImage - } - - if newProjectConfig.User == nil { - newProjectConfig.User = &apiServerConfig.DefaultProjectUser - } - - res, err = apiClient.ProjectConfigAPI.SetProjectConfig(ctx).ProjectConfig(newProjectConfig).Execute() - if err != nil { - return nil, apiclient_util.HandleErrorResponse(res, err) - } - - return &newProjectConfig.Name, nil -} - -func GetExistingProjectConfigNames(apiClient *apiclient.APIClient) ([]string, error) { - var existingProjectConfigNames []string - - existingProjectConfigs, res, err := apiClient.ProjectConfigAPI.ListProjectConfigs(context.Background()).Execute() - if err != nil { - return nil, apiclient_util.HandleErrorResponse(res, err) - } - - for _, pc := range existingProjectConfigs { - existingProjectConfigNames = append(existingProjectConfigNames, pc.Name) - } - - return existingProjectConfigNames, nil -} - -var nameFlag string - -var projectConfigurationFlags = workspace_util.ProjectConfigurationFlags{ - Builder: new(views_util.BuildChoice), - CustomImage: new(string), - CustomImageUser: new(string), - Branches: new([]string), - DevcontainerPath: new(string), - EnvVars: new([]string), - Manual: new(bool), - GitProviderConfig: new(string), -} - -func init() { - projectConfigAddCmd.Flags().StringVar(&nameFlag, "name", "", "Specify the project config name") - workspace_util.AddProjectConfigurationFlags(projectConfigAddCmd, projectConfigurationFlags, false) -} diff --git a/pkg/cmd/projectconfig/delete.go b/pkg/cmd/projectconfig/delete.go deleted file mode 100644 index 3944047917..0000000000 --- a/pkg/cmd/projectconfig/delete.go +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package projectconfig - -import ( - "context" - "fmt" - - "github.com/charmbracelet/huh" - apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" - "github.com/daytonaio/daytona/pkg/apiclient" - "github.com/daytonaio/daytona/pkg/views" - views_util "github.com/daytonaio/daytona/pkg/views/util" - "github.com/daytonaio/daytona/pkg/views/workspace/selection" - log "github.com/sirupsen/logrus" - "github.com/spf13/cobra" -) - -var allFlag bool -var yesFlag bool -var forceFlag bool - -var projectConfigDeleteCmd = &cobra.Command{ - Use: "delete", - Aliases: []string{"remove", "rm"}, - Short: "Delete a project config", - Args: cobra.MaximumNArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { - var selectedProjectConfig *apiclient.ProjectConfig - var selectedProjectConfigName string - - apiClient, err := apiclient_util.GetApiClient(nil) - if err != nil { - return err - } - - if allFlag { - if !yesFlag { - form := huh.NewForm( - huh.NewGroup( - huh.NewConfirm(). - Title("Delete all project configs?"). - Description("Are you sure you want to delete all project configs?"). - Value(&yesFlag), - ), - ).WithTheme(views.GetCustomTheme()) - - err := form.Run() - if err != nil { - return err - } - - if !yesFlag { - fmt.Println("Operation canceled.") - return nil - } - } - - projectConfigs, res, err := apiClient.ProjectConfigAPI.ListProjectConfigs(context.Background()).Execute() - if err != nil { - return apiclient_util.HandleErrorResponse(res, err) - } - - if len(projectConfigs) == 0 { - views_util.NotifyEmptyProjectConfigList(false) - return nil - } - - for _, projectConfig := range projectConfigs { - selectedProjectConfigName = projectConfig.Name - res, err := apiClient.ProjectConfigAPI.DeleteProjectConfig(context.Background(), selectedProjectConfigName).Execute() - if err != nil { - log.Error(apiclient_util.HandleErrorResponse(res, err)) - continue - } - views.RenderInfoMessage("Deleted project config: " + selectedProjectConfigName) - } - return nil - } - - if len(args) == 0 { - projectConfigs, res, err := apiClient.ProjectConfigAPI.ListProjectConfigs(context.Background()).Execute() - if err != nil { - return apiclient_util.HandleErrorResponse(res, err) - } - - if len(projectConfigs) == 0 { - views.RenderInfoMessage("No project configs found") - return nil - } - - selectedProjectConfig = selection.GetProjectConfigFromPrompt(projectConfigs, 0, false, false, "Delete") - if selectedProjectConfig == nil { - return nil - } - selectedProjectConfigName = selectedProjectConfig.Name - } else { - selectedProjectConfigName = args[0] - } - - res, err := apiClient.ProjectConfigAPI.DeleteProjectConfig(context.Background(), selectedProjectConfigName).Force(forceFlag).Execute() - if err != nil { - return apiclient_util.HandleErrorResponse(res, err) - } - - views.RenderInfoMessage("Project config deleted successfully") - return nil - }, -} - -func init() { - projectConfigDeleteCmd.Flags().BoolVarP(&allFlag, "all", "a", false, "Delete all project configs") - projectConfigDeleteCmd.Flags().BoolVarP(&yesFlag, "yes", "y", false, "Confirm deletion without prompt") - projectConfigDeleteCmd.Flags().BoolVarP(&forceFlag, "force", "f", false, "Force delete prebuild") -} diff --git a/pkg/cmd/projectconfig/export.go b/pkg/cmd/projectconfig/export.go deleted file mode 100644 index 22d7d53995..0000000000 --- a/pkg/cmd/projectconfig/export.go +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package projectconfig - -import ( - "context" - "encoding/json" - "fmt" - "net/http" - - "github.com/atotto/clipboard" - apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" - "github.com/daytonaio/daytona/pkg/apiclient" - "github.com/daytonaio/daytona/pkg/cmd/format" - "github.com/daytonaio/daytona/pkg/views" - views_util "github.com/daytonaio/daytona/pkg/views/util" - "github.com/daytonaio/daytona/pkg/views/workspace/selection" - "github.com/spf13/cobra" -) - -var projectConfigExportCmd = &cobra.Command{ - Use: "export", - Aliases: []string{"exp"}, - Short: "Export a project config", - Args: cobra.MaximumNArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { - var selectedProjectConfig *apiclient.ProjectConfig - ctx := context.Background() - - apiClient, err := apiclient_util.GetApiClient(nil) - if err != nil { - return err - } - - if allFlag { - projectConfigs, res, err := apiClient.ProjectConfigAPI.ListProjectConfigs(ctx).Execute() - if err != nil { - return apiclient_util.HandleErrorResponse(res, err) - } - - if len(projectConfigs) == 0 { - views_util.NotifyEmptyProjectConfigList(true) - return nil - } - - return exportProjectConfigs(projectConfigs) - } - - if len(args) == 0 { - projectConfigs, res, err := apiClient.ProjectConfigAPI.ListProjectConfigs(ctx).Execute() - if err != nil { - return apiclient_util.HandleErrorResponse(res, err) - } - - if len(projectConfigs) == 0 { - views_util.NotifyEmptyProjectConfigList(true) - return nil - } - - if format.FormatFlag != "" { - format.UnblockStdOut() - } - - selectedProjectConfig = selection.GetProjectConfigFromPrompt(projectConfigs, 0, false, false, "Export") - if selectedProjectConfig == nil { - return nil - } - - if format.FormatFlag != "" { - format.BlockStdOut() - } - } else { - var res *http.Response - selectedProjectConfig, res, err = apiClient.ProjectConfigAPI.GetProjectConfig(ctx, args[0]).Execute() - if err != nil { - return apiclient_util.HandleErrorResponse(res, err) - } - } - - return exportProjectConfigs([]apiclient.ProjectConfig{*selectedProjectConfig}) - }, -} - -func init() { - projectConfigExportCmd.Flags().BoolVarP(&allFlag, "all", "a", false, "Export all project configs") - format.RegisterFormatFlag(projectConfigExportCmd) -} - -func exportProjectConfigs(projectConfigs []apiclient.ProjectConfig) error { - if len(projectConfigs) == 0 { - return nil - } - - var pbFlag bool - - for i := range projectConfigs { - projectConfigs[i].GitProviderConfigId = nil - if projectConfigs[i].Prebuilds != nil { - projectConfigs[i].Prebuilds = nil - pbFlag = true - } - } - - var data []byte - var err error - - if len(projectConfigs) == 1 { - data, err = json.MarshalIndent(projectConfigs[0], "", " ") - views.RenderContainerLayout("Prebuilds have been removed from the config.") - } else { - data, err = json.MarshalIndent(projectConfigs, "", " ") - if pbFlag { - views.RenderContainerLayout("Prebuilds have been removed from your configs.") - } - } - - if format.FormatFlag != "" { - if len(projectConfigs) == 1 { - formattedData := format.NewFormatter(projectConfigs[0]) - formattedData.Print() - } else { - formattedData := format.NewFormatter(projectConfigs) - formattedData.Print() - } - return nil - } - - if err != nil { - return err - } - - fmt.Println(string(data)) - - if err := clipboard.WriteAll(string(data)); err == nil { - views.RenderContainerLayout(views.GetInfoMessage("The config(s) have been copied to your clipboard.")) - } else { - views.RenderContainerLayout(views.GetInfoMessage("Could not copy the config(s) to your clipboard.")) - } - - return nil -} diff --git a/pkg/cmd/projectconfig/import.go b/pkg/cmd/projectconfig/import.go deleted file mode 100644 index 238ab4ce6b..0000000000 --- a/pkg/cmd/projectconfig/import.go +++ /dev/null @@ -1,242 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package projectconfig - -import ( - "context" - "encoding/json" - "fmt" - "io" - "net/url" - "os" - - "github.com/charmbracelet/huh" - apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" - "github.com/daytonaio/daytona/pkg/apiclient" - "github.com/daytonaio/daytona/pkg/views" - views_util "github.com/daytonaio/daytona/pkg/views/util" - "github.com/daytonaio/daytona/pkg/views/workspace/create" - "github.com/daytonaio/daytona/pkg/views/workspace/selection" - "github.com/spf13/cobra" -) - -var filePath string - -var projectConfigImportCmd = &cobra.Command{ - Use: "import", - Aliases: []string{"imp"}, - Short: "Import project config from JSON", - Args: cobra.MaximumNArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { - var inputText string - ctx := context.Background() - - apiClient, err := apiclient_util.GetApiClient(nil) - if err != nil { - return err - } - - projectConfigList, res, err := apiClient.ProjectConfigAPI.ListProjectConfigs(ctx).Execute() - if err != nil { - return apiclient_util.HandleErrorResponse(res, err) - } - - if filePath != "" { - if filePath == "-" { - inputBytes, err := io.ReadAll(os.Stdin) - if err != nil { - return fmt.Errorf("error reading stdin: %v", err) - } - inputText = string(inputBytes) - } else { - inputBytes, err := os.ReadFile(filePath) - if err != nil { - return fmt.Errorf("error reading file: %v", err) - } - inputText = string(inputBytes) - } - - } else { - form := huh.NewForm( - huh.NewGroup( - huh.NewText(). - Title("Import Project-Config"). - Description("Enter Project-Config as a JSON or an array of JSON objects"). - CharLimit(-1). - Value(&inputText), - ), - ).WithTheme(views.GetCustomTheme()).WithHeight(20) - err = form.Run() - if err != nil { - return err - } - } - - var config apiclient.ProjectConfig - err = json.Unmarshal([]byte(inputText), &config) - if err == nil { - err = importProjectConfig(ctx, apiClient, config, &projectConfigList) - if err != nil { - return fmt.Errorf("error importing project config: %v", err) - } - } else { - var configs []apiclient.ProjectConfig - err = json.Unmarshal([]byte(inputText), &configs) - if err != nil { - return fmt.Errorf("invalid JSON input: %v", err) - } - - for _, config := range configs { - err = importProjectConfig(ctx, apiClient, config, &projectConfigList) - if err != nil { - return fmt.Errorf("error importing project config: %v", err) - } - } - } - return nil - }, -} - -func init() { - projectConfigImportCmd.Flags().StringVarP(&filePath, "file", "f", "", "Import project config from a JSON file. Use '-' to read from stdin.") -} - -func isProjectConfigAlreadyExists(configName string, projectConfigList *[]apiclient.ProjectConfig) bool { - for _, projectConfig := range *projectConfigList { - if projectConfig.Name == configName { - return true - } - } - return false -} - -func importProjectConfig(ctx context.Context, apiClient *apiclient.APIClient, config apiclient.ProjectConfig, projectConfigList *[]apiclient.ProjectConfig) error { - if isProjectConfigAlreadyExists(config.Name, projectConfigList) { - return fmt.Errorf("project config already present with name \"%s\"", config.Name) - } - - var verifiedGitProvider bool - if config.GitProviderConfigId != nil { - _, _, err := apiClient.GitProviderAPI.GetGitProvider(ctx, *config.GitProviderConfigId).Execute() - if err == nil { - verifiedGitProvider = true - } - } - - var gitProviders []apiclient.GitProvider - - if !verifiedGitProvider { - var err error - gitProviders, _, err = apiClient.GitProviderAPI.ListGitProvidersForUrl(ctx, url.QueryEscape(config.RepositoryUrl)).Execute() - if err != nil { - return fmt.Errorf("error fetching Git providers: %v", err) - } - - if len(gitProviders) == 0 { - gitProviderConfigId, _, err := apiClient.GitProviderAPI.GetGitProviderIdForUrl(ctx, url.QueryEscape(config.RepositoryUrl)).Execute() - if err != nil { - return fmt.Errorf("error fetching Git provider: %v", err) - } - config.GitProviderConfigId = &gitProviderConfigId - } - - if len(gitProviders) == 1 && config.GitProviderConfigId == nil { - config.GitProviderConfigId = &gitProviders[0].Id - } else if len(gitProviders) > 1 && config.GitProviderConfigId == nil { - selectedGitProvider := selection.GetGitProviderConfigFromPrompt(selection.GetGitProviderConfigParams{ - GitProviderConfigs: gitProviders, - ActionVerb: "Use", - }) - config.GitProviderConfigId = &selectedGitProvider.Id - } - } - - apiServerConfig, res, err := apiClient.ServerAPI.GetConfig(context.Background()).Execute() - if err != nil { - return apiclient_util.HandleErrorResponse(res, err) - } - - newProjectConfig := apiclient.CreateProjectConfigDTO{ - Name: config.Name, - BuildConfig: config.BuildConfig, - Image: &config.Image, - User: &config.User, - RepositoryUrl: config.RepositoryUrl, - EnvVars: config.EnvVars, - GitProviderConfigId: config.GitProviderConfigId, - } - - if newProjectConfig.Image == nil { - newProjectConfig.Image = &apiServerConfig.DefaultProjectImage - } - - if newProjectConfig.User == nil { - newProjectConfig.User = &apiServerConfig.DefaultProjectUser - } - - existingProjectConfigNames, err := GetExistingProjectConfigNames(apiClient) - if err != nil { - return err - } - - apiServerConfig, res, err = apiClient.ServerAPI.GetConfig(context.Background()).Execute() - if err != nil { - return apiclient_util.HandleErrorResponse(res, err) - } - - projectDefaults := &views_util.ProjectConfigDefaults{ - BuildChoice: views_util.AUTOMATIC, - Image: &apiServerConfig.DefaultProjectImage, - ImageUser: &apiServerConfig.DefaultProjectUser, - DevcontainerFilePath: create.DEVCONTAINER_FILEPATH, - } - - createDto := []apiclient.CreateProjectDTO{ - { - Name: config.Name, - Source: apiclient.CreateProjectSourceDTO{ - Repository: apiclient.GitRepository{ - Url: config.RepositoryUrl, - }, - }, - BuildConfig: config.BuildConfig, - EnvVars: config.EnvVars, - GitProviderConfigId: config.GitProviderConfigId, - }, - } - - create.ProjectsConfigurationChanged, err = create.RunProjectConfiguration(&createDto, *projectDefaults, true) - if err != nil { - return err - } - - submissionFormConfig := create.SubmissionFormConfig{ - ChosenName: &config.Name, - SuggestedName: config.Name, - ExistingNames: existingProjectConfigNames, - ProjectList: &createDto, - NameLabel: "Project config", - Defaults: projectDefaults, - } - - confirmation := true - err = create.RunSubmissionForm(submissionFormConfig, &confirmation) - if err != nil { - return err - } - - if confirmation { - res, err = apiClient.ProjectConfigAPI.SetProjectConfig(ctx).ProjectConfig(newProjectConfig).Execute() - if err != nil { - return apiclient_util.HandleErrorResponse(res, err) - } - - *projectConfigList = append(*projectConfigList, config) - views.RenderInfoMessage(fmt.Sprintf("Project config %s imported successfully", newProjectConfig.Name)) - return nil - } - - views.RenderInfoMessage(fmt.Sprintf("Project config %s import cancelled", newProjectConfig.Name)) - return nil -} diff --git a/pkg/cmd/projectconfig/projectconfig.go b/pkg/cmd/projectconfig/projectconfig.go deleted file mode 100644 index d5ccdce6f7..0000000000 --- a/pkg/cmd/projectconfig/projectconfig.go +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package projectconfig - -import ( - "github.com/daytonaio/daytona/internal/util" - "github.com/spf13/cobra" -) - -var ProjectConfigCmd = &cobra.Command{ - Use: "project-config", - Short: "Manage project configs", - Aliases: []string{"pc"}, - GroupID: util.WORKSPACE_GROUP, -} - -func init() { - ProjectConfigCmd.AddCommand(projectConfigListCmd) - ProjectConfigCmd.AddCommand(projectConfigInfoCmd) - ProjectConfigCmd.AddCommand(projectConfigAddCmd) - ProjectConfigCmd.AddCommand(projectConfigUpdateCmd) - ProjectConfigCmd.AddCommand(projectConfigSetDefaultCmd) - ProjectConfigCmd.AddCommand(projectConfigDeleteCmd) - ProjectConfigCmd.AddCommand(projectConfigExportCmd) - ProjectConfigCmd.AddCommand(projectConfigImportCmd) -} diff --git a/pkg/cmd/projectconfig/setdefault.go b/pkg/cmd/projectconfig/setdefault.go deleted file mode 100644 index 242f374e03..0000000000 --- a/pkg/cmd/projectconfig/setdefault.go +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package projectconfig - -import ( - "context" - "fmt" - - apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" - "github.com/daytonaio/daytona/pkg/views" - views_util "github.com/daytonaio/daytona/pkg/views/util" - "github.com/daytonaio/daytona/pkg/views/workspace/selection" - "github.com/spf13/cobra" -) - -var projectConfigSetDefaultCmd = &cobra.Command{ - Use: "set-default", - Short: "Set project config info", - Args: cobra.MaximumNArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { - var projectConfigName string - ctx := context.Background() - - apiClient, err := apiclient_util.GetApiClient(nil) - if err != nil { - return err - } - - if len(args) == 0 { - projectConfigList, res, err := apiClient.ProjectConfigAPI.ListProjectConfigs(ctx).Execute() - if err != nil { - return apiclient_util.HandleErrorResponse(res, err) - } - - if len(projectConfigList) == 0 { - views_util.NotifyEmptyProjectConfigList(true) - return nil - } - - projectConfig := selection.GetProjectConfigFromPrompt(projectConfigList, 0, false, false, "Make Default") - if projectConfig == nil { - return nil - } - projectConfigName = projectConfig.Name - } else { - projectConfigName = args[0] - } - - res, err := apiClient.ProjectConfigAPI.SetDefaultProjectConfig(ctx, projectConfigName).Execute() - if err != nil { - return apiclient_util.HandleErrorResponse(res, err) - } - - views.RenderInfoMessage(fmt.Sprintf("Project config '%s' set as default", projectConfigName)) - return nil - }, -} - -func init() { -} diff --git a/pkg/cmd/provider/install.go b/pkg/cmd/provider/install.go index f5d15b2808..f0cb05e601 100644 --- a/pkg/cmd/provider/install.go +++ b/pkg/cmd/provider/install.go @@ -5,65 +5,75 @@ package provider import ( "context" - "errors" "fmt" - "slices" - "strings" - "github.com/charmbracelet/huh" apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" "github.com/daytonaio/daytona/pkg/apiclient" + cmd_common "github.com/daytonaio/daytona/pkg/cmd/common" "github.com/daytonaio/daytona/pkg/common" - "github.com/daytonaio/daytona/pkg/os" - "github.com/daytonaio/daytona/pkg/provider/manager" "github.com/daytonaio/daytona/pkg/views" - "github.com/daytonaio/daytona/pkg/views/provider" - provider_view "github.com/daytonaio/daytona/pkg/views/provider" - "github.com/daytonaio/daytona/pkg/views/target" + "github.com/daytonaio/daytona/pkg/views/provider/install" views_util "github.com/daytonaio/daytona/pkg/views/util" "github.com/spf13/cobra" ) var yesFlag bool -var providerInstallCmd = &cobra.Command{ +var installCmd = &cobra.Command{ Use: "install", Short: "Install provider", - Args: cobra.NoArgs, - Aliases: []string{"i"}, + Args: cobra.MaximumNArgs(1), + Aliases: cmd_common.GetAliases("install"), RunE: func(cmd *cobra.Command, args []string) error { + var selectedRunnerId string + + ctx := context.Background() + apiClient, err := apiclient_util.GetApiClient(nil) if err != nil { return err } - serverConfig, res, err := apiClient.ServerAPI.GetConfigExecute(apiclient.ApiGetConfigRequest{}) - if err != nil { - return apiclient_util.HandleErrorResponse(res, err) - } + if len(args) == 0 { + selectedRunner, err := cmd_common.GetRunnerFlow(apiClient, "Manage Providers") + if err != nil { + if common.IsCtrlCAbort(err) { + return nil + } else { + return err + } + } - providerManager := manager.NewProviderManager(manager.ProviderManagerConfig{RegistryUrl: serverConfig.RegistryUrl}) + if selectedRunner == nil { + return nil + } - providersManifest, err := providerManager.GetProvidersManifest() - if err != nil { - return err + selectedRunnerId = selectedRunner.Id + } else { + selectedRunnerId = args[0] } - if providersManifest == nil { - return errors.New("could not get providers manifest") + availableProviderList, res, err := apiClient.ProviderAPI.ListProvidersForInstall(ctx).Execute() + if err != nil { + return apiclient_util.HandleErrorResponse(res, err) } - providersManifestLatest := providersManifest.GetLatestVersions() - if providersManifestLatest == nil { - return errors.New("could not get providers manifest") + var latestProviderList []apiclient.ProviderDTO + for _, provider := range availableProviderList { + if provider.Latest { + latestProviderList = append(latestProviderList, provider) + } } - providerList := GetProviderListFromManifest(providersManifestLatest) specificProviderName := "Select a specific version" - specificProviderVersion := "" - providerList = append(providerList, apiclient.Provider{Name: specificProviderName, Label: &specificProviderName, Version: specificProviderVersion}) - - providerToInstall, err := provider.GetProviderFromPrompt(provider.ProviderListToView(providerList), "Choose a Provider to Install", false) + latestProviderList = append(latestProviderList, apiclient.ProviderDTO{ + Name: specificProviderName, + Label: &specificProviderName, + Version: "", + Latest: false, + }) + + providerToInstall, err := install.GetProviderFromInstallPrompt(install.ProviderInstallListToView(latestProviderList), "Choose a Provider to Install", false) if err != nil { if common.IsCtrlCAbort(err) { return nil @@ -77,9 +87,7 @@ var providerInstallCmd = &cobra.Command{ } if providerToInstall.Name == specificProviderName { - providerList = GetProviderListFromManifest(providersManifest) - - providerToInstall, err = provider.GetProviderFromPrompt(provider.ProviderListToView(providerList), "Choose a specific provider to install", false) + providerToInstall, err = install.GetProviderFromInstallPrompt(install.ProviderInstallListToView(availableProviderList), "Choose a specific provider to install", false) if err != nil { if common.IsCtrlCAbort(err) { return nil @@ -93,131 +101,28 @@ var providerInstallCmd = &cobra.Command{ } } - err = InstallProvider(apiClient, *providerToInstall, providersManifest) + err = InstallProvider(apiClient, selectedRunnerId, *providerToInstall) if err != nil { return err } views.RenderInfoMessageBold(fmt.Sprintf("Provider %s has been successfully installed", providerToInstall.Name)) - - targets, res, err := apiClient.TargetAPI.ListTargets(context.Background()).Execute() - if err != nil { - return apiclient_util.HandleErrorResponse(res, err) - } - - if slices.ContainsFunc(targets, func(t apiclient.ProviderTarget) bool { - return t.ProviderInfo.Name == providerToInstall.Name - }) { - return nil - } - - if !yesFlag { - form := huh.NewForm( - huh.NewGroup( - huh.NewConfirm(). - Title("Add a Target?"). - Value(&yesFlag), - ), - ).WithTheme(views.GetCustomTheme()) - - err := form.Run() - if err != nil { - return err - } - } - - if yesFlag { - targetManifest, res, err := apiClient.ProviderAPI.GetTargetManifest(context.Background(), providerToInstall.Name).Execute() - if err != nil { - return apiclient_util.HandleErrorResponse(res, err) - } - - targetToSet := &target.TargetView{ - Options: "{}", - ProviderInfo: target.ProviderInfo{ - Name: providerToInstall.Name, - Version: providerToInstall.Version, - }, - } - - err = target.NewTargetNameInput(&targetToSet.Name, []string{}) - if err != nil { - return err - } - - err = target.SetTargetForm(targetToSet, *targetManifest) - if err != nil { - return err - } - - targetData := apiclient.CreateProviderTargetDTO{ - Name: targetToSet.Name, - Options: targetToSet.Options, - ProviderInfo: apiclient.ProviderProviderInfo{ - Name: targetToSet.ProviderInfo.Name, - Version: targetToSet.ProviderInfo.Version, - }, - } - - res, err = apiClient.TargetAPI.SetTarget(context.Background()).Target(targetData).Execute() - if err != nil { - return apiclient_util.HandleErrorResponse(res, err) - } - if err != nil { - return err - } - - views.RenderInfoMessage("Target set successfully") - } return nil }, } func init() { - providerInstallCmd.Flags().BoolVarP(&yesFlag, "yes", "y", false, "Automatically confirm any prompts") + installCmd.Flags().BoolVarP(&yesFlag, "yes", "y", false, "Automatically confirm any prompts") } -func GetProviderListFromManifest(manifest *manager.ProvidersManifest) []apiclient.Provider { - providerList := []apiclient.Provider{} - for providerName, providerManifest := range *manifest { - for version := range providerManifest.Versions { - providerList = append(providerList, apiclient.Provider{ - Name: providerName, - Label: providerManifest.Label, - Version: version, - }) - } - } - - slices.SortFunc(providerList, func(a, b apiclient.Provider) int { - return strings.Compare(a.Name, b.Name) - }) - - return providerList -} - -func ConvertOSToStringMap(downloadUrls map[os.OperatingSystem]string) map[string]string { - stringMap := map[string]string{} - for os, url := range downloadUrls { - stringMap[string(os)] = url - } - - return stringMap -} - -func InstallProvider(apiClient *apiclient.APIClient, providerToInstall provider_view.ProviderView, providersManifest *manager.ProvidersManifest) error { - downloadUrls := ConvertOSToStringMap((*providersManifest)[providerToInstall.Name].Versions[providerToInstall.Version].DownloadUrls) +func InstallProvider(apiClient *apiclient.APIClient, runnerId string, providerToInstall install.ProviderInstallView) error { err := views_util.WithInlineSpinner("Installing", func() error { - res, err := apiClient.ProviderAPI.InstallProviderExecute(apiclient.ApiInstallProviderRequest{}.Provider(apiclient.InstallProviderRequest{ - Name: providerToInstall.Name, - DownloadUrls: downloadUrls, - })) - + res, err := apiClient.ProviderAPI.InstallProvider(context.Background(), runnerId, providerToInstall.Name).ProviderVersion(providerToInstall.Version).Execute() if err != nil { return apiclient_util.HandleErrorResponse(res, err) } - return nil + return cmd_common.AwaitProviderInstalled(runnerId, providerToInstall.Name, providerToInstall.Version) }) return err diff --git a/pkg/cmd/provider/list.go b/pkg/cmd/provider/list.go index 1bac57a6d7..dd9da4b4f6 100644 --- a/pkg/cmd/provider/list.go +++ b/pkg/cmd/provider/list.go @@ -6,20 +6,18 @@ package provider import ( "context" - "github.com/daytonaio/daytona/internal/util" apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" - "github.com/daytonaio/daytona/pkg/apiclient" + "github.com/daytonaio/daytona/pkg/cmd/common" "github.com/daytonaio/daytona/pkg/cmd/format" "github.com/daytonaio/daytona/pkg/views/provider" - provider_view "github.com/daytonaio/daytona/pkg/views/provider" "github.com/spf13/cobra" ) -var providerListCmd = &cobra.Command{ +var listCmd = &cobra.Command{ Use: "list", Short: "List installed providers", Args: cobra.NoArgs, - Aliases: []string{"ls"}, + Aliases: common.GetAliases("list"), RunE: func(cmd *cobra.Command, args []string) error { ctx := context.Background() @@ -44,43 +42,6 @@ var providerListCmd = &cobra.Command{ }, } -func GetProviderViewOptions(apiClient *apiclient.APIClient, latestProviders []apiclient.Provider, ctx context.Context) ([]provider_view.ProviderView, error) { - var result []provider_view.ProviderView - - installedProviders, res, err := apiClient.ProviderAPI.ListProviders(ctx).Execute() - if err != nil { - return nil, apiclient_util.HandleErrorResponse(res, err) - } - - providerMap := make(map[string]provider_view.ProviderView) - - for _, installedProvider := range installedProviders { - providerMap[installedProvider.Name] = provider_view.ProviderView{ - Name: installedProvider.Name, - Label: installedProvider.Label, - Version: installedProvider.Version, - Installed: util.Pointer(true), - } - } - - for _, latestProvider := range latestProviders { - if _, exists := providerMap[latestProvider.Name]; !exists { - providerMap[latestProvider.Name] = provider_view.ProviderView{ - Name: latestProvider.Name, - Label: latestProvider.Label, - Version: latestProvider.Version, - Installed: util.Pointer(false), - } - } - } - - for _, provider := range providerMap { - result = append(result, provider) - } - - return result, nil -} - func init() { - format.RegisterFormatFlag(providerListCmd) + format.RegisterFormatFlag(listCmd) } diff --git a/pkg/cmd/provider/provider.go b/pkg/cmd/provider/provider.go index 5c38d5a66d..552c91f4db 100644 --- a/pkg/cmd/provider/provider.go +++ b/pkg/cmd/provider/provider.go @@ -11,12 +11,14 @@ import ( var ProviderCmd = &cobra.Command{ Use: "provider", Short: "Manage providers", + Args: cobra.NoArgs, GroupID: util.SERVER_GROUP, + Aliases: []string{"providers"}, } func init() { - ProviderCmd.AddCommand(providerListCmd) - ProviderCmd.AddCommand(providerUninstallCmd) - ProviderCmd.AddCommand(providerInstallCmd) - ProviderCmd.AddCommand(providerUpdateCmd) + ProviderCmd.AddCommand(listCmd) + ProviderCmd.AddCommand(uninstallCmd) + ProviderCmd.AddCommand(installCmd) + ProviderCmd.AddCommand(updateCmd) } diff --git a/pkg/cmd/provider/uninstall.go b/pkg/cmd/provider/uninstall.go index 08c153d4e8..fd2ca8b343 100644 --- a/pkg/cmd/provider/uninstall.go +++ b/pkg/cmd/provider/uninstall.go @@ -8,7 +8,7 @@ import ( "fmt" "github.com/daytonaio/daytona/internal/util/apiclient" - apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" + cmd_common "github.com/daytonaio/daytona/pkg/cmd/common" "github.com/daytonaio/daytona/pkg/common" "github.com/daytonaio/daytona/pkg/views" "github.com/daytonaio/daytona/pkg/views/provider" @@ -16,22 +16,43 @@ import ( "github.com/spf13/cobra" ) -var providerUninstallCmd = &cobra.Command{ +var uninstallCmd = &cobra.Command{ Use: "uninstall", Short: "Uninstall provider", Args: cobra.NoArgs, - Aliases: []string{"u"}, + Aliases: cmd_common.GetAliases("uninstall"), RunE: func(cmd *cobra.Command, args []string) error { + var selectedRunnerId string + ctx := context.Background() - apiClient, err := apiclient_util.GetApiClient(nil) + apiClient, err := apiclient.GetApiClient(nil) if err != nil { return err } + if len(args) == 0 { + selectedRunner, err := cmd_common.GetRunnerFlow(apiClient, "Manage Providers") + if err != nil { + if common.IsCtrlCAbort(err) { + return nil + } else { + return err + } + } + + if selectedRunner == nil { + return nil + } + + selectedRunnerId = selectedRunner.Id + } else { + selectedRunnerId = args[0] + } + providerList, res, err := apiClient.ProviderAPI.ListProviders(ctx).Execute() if err != nil { - return apiclient_util.HandleErrorResponse(res, err) + return apiclient.HandleErrorResponse(res, err) } if len(providerList) == 0 { @@ -52,7 +73,7 @@ var providerUninstallCmd = &cobra.Command{ return nil } - res, err = apiClient.ProviderAPI.UninstallProvider(ctx, providerToUninstall.Name).Execute() + res, err = apiClient.ProviderAPI.UninstallProvider(ctx, selectedRunnerId, providerToUninstall.Name).Execute() if err != nil { return apiclient.HandleErrorResponse(res, err) } diff --git a/pkg/cmd/provider/update.go b/pkg/cmd/provider/update.go index 822cbdc900..90d2330b56 100644 --- a/pkg/cmd/provider/update.go +++ b/pkg/cmd/provider/update.go @@ -8,23 +8,23 @@ import ( "fmt" apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" - "github.com/daytonaio/daytona/pkg/apiclient" + cmd_common "github.com/daytonaio/daytona/pkg/cmd/common" "github.com/daytonaio/daytona/pkg/common" - "github.com/daytonaio/daytona/pkg/provider/manager" "github.com/daytonaio/daytona/pkg/views/provider" views_util "github.com/daytonaio/daytona/pkg/views/util" - log "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) var allFlag bool -var providerUpdateCmd = &cobra.Command{ +var updateCmd = &cobra.Command{ Use: "update", Short: "Update provider", Args: cobra.NoArgs, - Aliases: []string{"up"}, + Aliases: cmd_common.GetAliases("update"), RunE: func(cmd *cobra.Command, args []string) error { + var selectedRunnerId string + ctx := context.Background() apiClient, err := apiclient_util.GetApiClient(nil) @@ -32,6 +32,25 @@ var providerUpdateCmd = &cobra.Command{ return err } + if len(args) == 0 { + selectedRunner, err := cmd_common.GetRunnerFlow(apiClient, "Manage Providers") + if err != nil { + if common.IsCtrlCAbort(err) { + return nil + } else { + return err + } + } + + if selectedRunner == nil { + return nil + } + + selectedRunnerId = selectedRunner.Id + } else { + selectedRunnerId = args[0] + } + providerList, res, err := apiClient.ProviderAPI.ListProviders(ctx).Execute() if err != nil { return apiclient_util.HandleErrorResponse(res, err) @@ -42,24 +61,12 @@ var providerUpdateCmd = &cobra.Command{ return nil } - serverConfig, res, err := apiClient.ServerAPI.GetConfigExecute(apiclient.ApiGetConfigRequest{}) - if err != nil { - return apiclient_util.HandleErrorResponse(res, err) - } - - providerManager := manager.NewProviderManager(manager.ProviderManagerConfig{RegistryUrl: serverConfig.RegistryUrl}) - - providersManifest, err := providerManager.GetProvidersManifest() - if err != nil { - return err - } - if allFlag { for _, provider := range providerList { fmt.Printf("Updating provider %s\n", provider.Name) - err := updateProvider(provider.Name, providersManifest, apiClient) + res, err := apiClient.ProviderAPI.UpdateProvider(context.Background(), selectedRunnerId, provider.Name).Execute() if err != nil { - log.Error(fmt.Sprintf("Failed to update provider %s: %s", provider.Name, err)) + return apiclient_util.HandleErrorResponse(res, err) } else { fmt.Printf("Provider %s has been successfully updated\n", provider.Name) } @@ -80,41 +87,16 @@ var providerUpdateCmd = &cobra.Command{ return nil } - err = updateProvider(providerToUpdate.Name, providersManifest, apiClient) + res, err = apiClient.ProviderAPI.UpdateProvider(context.Background(), selectedRunnerId, providerToUpdate.Name).ProviderVersion(providerToUpdate.Version).Execute() if err != nil { - return err + return apiclient_util.HandleErrorResponse(res, err) } - fmt.Printf("Provider %s has been successfully updated\n", providerToUpdate.Name) + fmt.Printf("Provider %s update is in progress\n", providerToUpdate.Name) return nil }, } -func updateProvider(providerName string, providersManifest *manager.ProvidersManifest, apiClient *apiclient.APIClient) error { - providerManifest, ok := (*providersManifest)[providerName] - if !ok { - return fmt.Errorf("provider %s not found in manifest", providerName) - } - - version, ok := providerManifest.Versions["latest"] - if !ok { - _, latest := providerManifest.FindLatestVersion() - version = *latest - } - - downloadUrls := ConvertOSToStringMap(version.DownloadUrls) - - res, err := apiClient.ProviderAPI.InstallProviderExecute(apiclient.ApiInstallProviderRequest{}.Provider(apiclient.InstallProviderRequest{ - Name: providerName, - DownloadUrls: downloadUrls, - })) - if err != nil { - return apiclient_util.HandleErrorResponse(res, err) - } - - return nil -} - func init() { - providerUpdateCmd.Flags().BoolVarP(&allFlag, "all", "a", false, "Update all providers") + updateCmd.Flags().BoolVarP(&allFlag, "all", "a", false, "Update all providers") } diff --git a/pkg/cmd/purge.go b/pkg/cmd/purge.go index 5c7f082d0c..38098c7da5 100644 --- a/pkg/cmd/purge.go +++ b/pkg/cmd/purge.go @@ -5,31 +5,32 @@ package cmd import ( "context" - "errors" "fmt" "os" + "path/filepath" + "strings" "github.com/daytonaio/daytona/cmd/daytona/config" "github.com/daytonaio/daytona/internal" "github.com/daytonaio/daytona/internal/util/apiclient" - "github.com/daytonaio/daytona/pkg/build" + "github.com/daytonaio/daytona/pkg/cmd/bootstrap" server_cmd "github.com/daytonaio/daytona/pkg/cmd/server" + "github.com/daytonaio/daytona/pkg/cmd/workspace/create" "github.com/daytonaio/daytona/pkg/posthogservice" "github.com/daytonaio/daytona/pkg/server" + "github.com/daytonaio/daytona/pkg/services" "github.com/daytonaio/daytona/pkg/telemetry" "github.com/daytonaio/daytona/pkg/views" view "github.com/daytonaio/daytona/pkg/views/purge" - log "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) -var yesFlag bool var forceFlag bool var purgeCmd = &cobra.Command{ Use: "purge", Short: "Purges all Daytona data from the current device", - Long: "Purges all Daytona data from the current device - including all workspaces, configuration files, and SSH files. This command is irreversible.", + Long: "Purges all Daytona data from the current device - including all local runner providers, configuration files and SSH files. This command is irreversible.", Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { var confirmCheck bool @@ -51,13 +52,8 @@ var purgeCmd = &cobra.Command{ return err } - buildRunnerConfig, err := build.GetConfig() - if err != nil { - return err - } - if c.ActiveProfileId != "default" { - if !yesFlag { + if !create.YesFlag { view.DefaultProfileNoticePrompt(&defaultProfileNoticeConfirm) if !defaultProfileNoticeConfirm { fmt.Println("Operation cancelled.") @@ -90,7 +86,7 @@ var purgeCmd = &cobra.Command{ } } - if !yesFlag { + if !create.YesFlag { view.ConfirmPrompt(&confirmCheck) if !confirmCheck { fmt.Println("Operation cancelled.") @@ -102,16 +98,12 @@ var purgeCmd = &cobra.Command{ ApiKey: internal.PosthogApiKey, Endpoint: internal.PosthogEndpoint, Version: internal.Version, + Source: telemetry.CLI_SOURCE, }) defer telemetryService.Close() - fmt.Println("Purging the server") - server, err := server_cmd.GetInstance(serverConfig, serverConfigDir, internal.Version, telemetryService) - if err != nil { - return err - } - buildRunner, err := server_cmd.GetBuildRunner(serverConfig, buildRunnerConfig, telemetryService) + server, err := bootstrap.GetInstance(serverConfig, serverConfigDir, internal.Version, telemetryService) if err != nil { return err } @@ -120,72 +112,52 @@ var purgeCmd = &cobra.Command{ ctx = context.WithValue(ctx, telemetry.CLIENT_ID_CONTEXT_KEY, config.GetClientId()) ctx = context.WithValue(ctx, telemetry.ENABLED_CONTEXT_KEY, c.TelemetryEnabled) - errCh := make(chan error) - - // Starting the build runner so it can be used to delete builds - err = buildRunner.Start() + // Get all targets, workspaces and builds to prompt user for resource purge + targets, err := server.TargetService.List(ctx, nil, services.TargetRetrievalParams{}) if err != nil { if !forceFlag { return err + } else { + fmt.Printf("Failed to get targets: %v\n", err) } } - go func() { - err := <-errCh - if err != nil { - if !forceFlag { - buildRunner.Stop() - log.Fatal(err) - } - } - }() - - headscaleServerStartedChan := make(chan struct{}) - headscaleServerErrChan := make(chan error) - - go func() { - err := server.TailscaleServer.Start(headscaleServerErrChan) - if err != nil { - headscaleServerErrChan <- err - return - } - headscaleServerStartedChan <- struct{}{} - }() - - localContainerRegistryErrChan := make(chan error) - - go func() { - if server.LocalContainerRegistry != nil { - localContainerRegistryErrChan <- server.LocalContainerRegistry.Start() + workspaces, err := server.WorkspaceService.List(ctx, services.WorkspaceRetrievalParams{}) + if err != nil { + if !forceFlag { + return err } else { - localContainerRegistryErrChan <- nil + fmt.Printf("Failed to get workspaces: %v\n", err) } - }() - - select { - case <-headscaleServerStartedChan: - go func() { - headscaleServerErrChan <- server.TailscaleServer.Connect() - }() - case err := <-headscaleServerErrChan: - return err } - err = <-localContainerRegistryErrChan + builds, err := server.BuildService.List(ctx, nil) if err != nil { - return err + if !forceFlag { + return err + } else { + fmt.Printf("Failed to get builds: %v\n", err) + } } - errs := server.Purge(ctx, forceFlag) - if len(errs) > 0 { - errMessage := "" - for _, err := range errs { - errMessage += fmt.Sprintf("Failed to purge: %v\n", err) + if len(targets) != 0 || len(workspaces) != 0 || len(builds) != 0 { + var continuePurge bool + commands := view.PurgeResourcesPrompt(&continuePurge, len(targets), len(workspaces), len(builds)) + if err != nil { + if !forceFlag { + return err + } else { + fmt.Printf("Failed to prompt for resource purge: %v\n", err) + } + } + if !continuePurge { + fmt.Printf("\nOperation cancelled.\nManually delete leftover resources for a complete purge by starting the server and running the following commands:\n\n%s\n", strings.Join(commands, "\n")) + return nil } - - return errors.New(errMessage) } + fmt.Println("Purging the server") + if server.LocalContainerRegistry != nil { fmt.Println("Purging local container registry...") err := server.LocalContainerRegistry.Purge() @@ -208,6 +180,34 @@ var purgeCmd = &cobra.Command{ } } + localRunnerConfig := server_cmd.GetLocalRunnerConfig(filepath.Join(serverConfigDir, "local-runner"), c.TelemetryEnabled, c.Id) + + params := bootstrap.LocalRunnerParams{ + ServerConfig: serverConfig, + RunnerConfig: localRunnerConfig, + ConfigDir: serverConfigDir, + TelemetryService: telemetryService, + } + + localRunner, err := bootstrap.GetLocalRunner(params) + if err != nil { + return err + } + + if localRunner != nil { + fmt.Println("Purging providers...") + err = localRunner.Purge(ctx) + if err != nil { + if !forceFlag { + return err + } else { + fmt.Printf("Failed to purge local runner providers: %v\n", err) + } + } else { + fmt.Println("Providers purged.") + } + } + fmt.Println("Server purged.") fmt.Println("\nDeleting the SSH configuration file") @@ -240,6 +240,6 @@ var purgeCmd = &cobra.Command{ } func init() { - purgeCmd.Flags().BoolVarP(&yesFlag, "yes", "y", false, "Execute purge without prompt") - purgeCmd.Flags().BoolVarP(&forceFlag, "force", "f", false, "Delete all workspaces by force") + purgeCmd.Flags().BoolVarP(&create.YesFlag, "yes", "y", false, "Execute purge without a prompt") + purgeCmd.Flags().BoolVarP(&forceFlag, "force", "f", false, "Delete all targets by force") } diff --git a/pkg/cmd/runner/config.go b/pkg/cmd/runner/config.go new file mode 100644 index 0000000000..4812e47a04 --- /dev/null +++ b/pkg/cmd/runner/config.go @@ -0,0 +1,39 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package runner + +import ( + view "github.com/daytonaio/daytona/pkg/views/runner" + "github.com/spf13/cobra" + + "github.com/daytonaio/daytona/pkg/cmd/format" + "github.com/daytonaio/daytona/pkg/runner" +) + +var configCmd = &cobra.Command{ + Use: "config", + Short: "Outputs Daytona Runner config", + RunE: func(cmd *cobra.Command, args []string) error { + config, err := runner.GetConfig() + if err != nil { + return err + } + + if format.FormatFlag != "" { + formattedData := format.NewFormatter(config) + formattedData.Print() + return nil + } + + view.RenderConfig(config, showKeyFlag) + return nil + }, +} + +var showKeyFlag bool + +func init() { + configCmd.Flags().BoolVarP(&showKeyFlag, "key", "k", false, "Show API Key") + format.RegisterFormatFlag(configCmd) +} diff --git a/pkg/cmd/runner/configure.go b/pkg/cmd/runner/configure.go new file mode 100644 index 0000000000..13fdaa7202 --- /dev/null +++ b/pkg/cmd/runner/configure.go @@ -0,0 +1,83 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package runner + +import ( + "errors" + + "github.com/daytonaio/daytona/pkg/runner" + "github.com/daytonaio/daytona/pkg/views" + runner_view "github.com/daytonaio/daytona/pkg/views/runner" + "github.com/spf13/cobra" +) + +var configureCmd = &cobra.Command{ + Use: "configure", + Short: "Configure Daytona Runner", + RunE: func(cmd *cobra.Command, args []string) error { + var configExisted bool + + config, err := runner.GetConfig() + if err != nil { + if errors.Is(err, runner.ErrConfigNotFound) { + configExisted = false + config, err = runner.GetDefaultConfig() + if err != nil { + return err + } + } else { + return err + } + } + + if idFlag != "" && nameFlag != "" && apiUrlFlag != "" && apiKeyFlag != "" { + config.Id = idFlag + config.Name = nameFlag + config.ServerApiUrl = apiUrlFlag + config.ServerApiKey = apiKeyFlag + config.TelemetryEnabled = !telemetryDisabled + } else { + config, err = runner_view.ConfigurationForm(config) + if err != nil { + return err + } + } + + if clientId != "" { + config.ClientId = clientId + } + + err = runner.Save(*config) + if err != nil { + return err + } + + infoMessage := "Runner configuration updated. " + + if configExisted { + infoMessage += "You need to restart the runner for the changes to take effect." + } else { + infoMessage += "To start running jobs, run 'daytona runner start'" + } + + views.RenderContainerLayout(views.GetInfoMessage(infoMessage)) + return nil + }, +} + +var idFlag string +var nameFlag string +var apiUrlFlag string +var apiKeyFlag string +var clientId string +var telemetryDisabled bool + +func init() { + configureCmd.Flags().StringVar(&idFlag, "id", "", "Runner ID") + configureCmd.Flags().StringVar(&nameFlag, "name", "", "Runner Name") + configureCmd.Flags().StringVar(&apiUrlFlag, "api-url", "", "Daytona Server API URL") + configureCmd.Flags().StringVar(&apiKeyFlag, "api-key", "", "Runner API Key") + configureCmd.Flags().StringVar(&clientId, "client-id", "", "Client ID") + configureCmd.Flags().BoolVar(&telemetryDisabled, "disable-telemetry", false, "Disable telemetry") +} diff --git a/pkg/cmd/runner/logs.go b/pkg/cmd/runner/logs.go new file mode 100644 index 0000000000..33d244da0e --- /dev/null +++ b/pkg/cmd/runner/logs.go @@ -0,0 +1,75 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package runner + +import ( + "context" + "errors" + "io" + + "github.com/daytonaio/daytona/pkg/cmd/common" + "github.com/daytonaio/daytona/pkg/logs" + "github.com/daytonaio/daytona/pkg/runner" + logs_view "github.com/daytonaio/daytona/pkg/views/logs" + "github.com/spf13/cobra" +) + +var followFlag bool + +var logsCmd = &cobra.Command{ + Use: "logs", + Short: "View runner logs", + Args: cobra.NoArgs, + Aliases: common.GetAliases("logs"), + RunE: func(cmd *cobra.Command, args []string) error { + c, err := runner.GetConfig() + if err != nil { + return err + } + + configDir, err := runner.GetConfigDir() + if err != nil { + return err + } + + loggerFactory := logs.NewLoggerFactory(logs.LoggerFactoryConfig{ + LogsDir: runner.GetLogsDir(configDir), + }) + + logReader, err := loggerFactory.CreateLogReader(c.Id) + if err != nil { + return err + } + + logs_view.SetupLongestPrefixLength([]string{c.Name}) + + entryChan := make(chan interface{}) + errChan := make(chan error) + go func() { + logs.ReadJSONLog(context.Background(), logReader, followFlag, entryChan, errChan) + }() + + go func() { + for entry := range entryChan { + logEntry, ok := entry.(logs.LogEntry) + if !ok || logEntry == (logs.LogEntry{}) { + continue + } + + logs_view.DisplayLogEntry(logEntry, logs_view.STATIC_INDEX) + } + }() + + err = <-errChan + if err != nil && !errors.Is(err, io.EOF) { + return err + } + + return nil + }, +} + +func init() { + logsCmd.Flags().BoolVarP(&followFlag, "follow", "f", false, "Follow logs") +} diff --git a/pkg/cmd/runner/purge.go b/pkg/cmd/runner/purge.go new file mode 100644 index 0000000000..c71aebbcbb --- /dev/null +++ b/pkg/cmd/runner/purge.go @@ -0,0 +1,112 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package runner + +import ( + "fmt" + "net" + + "github.com/charmbracelet/huh" + "github.com/daytonaio/daytona/pkg/runner" + "github.com/daytonaio/daytona/pkg/views" + "github.com/spf13/cobra" +) + +var yesFlag bool + +var purgeCmd = &cobra.Command{ + Use: "purge", + Short: "Purges the Daytona Runner", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + if !yesFlag { + var confirmCheck bool + + form := huh.NewForm( + huh.NewGroup( + huh.NewConfirm(). + Title("Purging will remove the entire Daytona Runner configuration from the system, are you sure you want to continue?"). + Description("This action is irreversible."). + Value(&confirmCheck), + ), + ).WithTheme(views.GetCustomTheme()) + + err := form.Run() + if err != nil { + return err + } + + if !confirmCheck { + fmt.Println("Operation cancelled.") + return nil + } + } + + cfg, err := runner.GetConfig() + if err != nil { + return err + } + + err = healthCheck(cfg.ApiPort) + if err == nil { + return runStopRunnerForm(cfg.ApiPort) + } + + return purgeRunner() + }, +} + +func healthCheck(apiPort int32) error { + _, err := net.Dial("tcp", fmt.Sprintf(":%d", apiPort)) + + return err +} + +func runStopRunnerForm(apiPort int32) error { + var runnerStoppedCheck bool + + form := huh.NewForm( + huh.NewGroup( + huh.NewConfirm(). + Title("Please stop the Daytona Runner before continuing by executing daytona runner stop command."). + Description("Purging all data requires the Daytona Runner to be stopped."). + Affirmative("Continue"). + Negative("Abort"). + Value(&runnerStoppedCheck), + ), + ).WithTheme(views.GetCustomTheme()) + + err := form.Run() + if err != nil { + return err + } + + if runnerStoppedCheck { + err = healthCheck(apiPort) + if err == nil { + views.RenderInfoMessage("The Daytona Runner is still running. Please stop it before continuing.") + return nil + } + } else { + fmt.Println("Operation cancelled.") + return nil + } + + return purgeRunner() +} + +func purgeRunner() error { + err := runner.DeleteConfigDir() + if err != nil { + return err + } + + views.RenderInfoMessageBold("The Daytona Runner has been purged from this device.") + + return nil +} + +func init() { + purgeCmd.Flags().BoolVarP(&yesFlag, "yes", "y", false, "Execute Daytona Runner purge without a prompt") +} diff --git a/pkg/cmd/runner/restart.go b/pkg/cmd/runner/restart.go new file mode 100644 index 0000000000..bd1cbf78eb --- /dev/null +++ b/pkg/cmd/runner/restart.go @@ -0,0 +1,43 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package runner + +import ( + "errors" + "fmt" + + "github.com/daytonaio/daytona/pkg/cmd/common/daemon" + "github.com/daytonaio/daytona/pkg/server" + "github.com/daytonaio/daytona/pkg/views" + "github.com/spf13/cobra" +) + +var restartCmd = &cobra.Command{ + Use: "restart", + Short: "Restarts the runner", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + views.RenderInfoMessage("Stopping the Daytona Runner daemon...") + err := daemon.Stop(svcConfig) + if err != nil { + if errors.Is(err, daemon.ErrDaemonNotInstalled) { + return fmt.Errorf("%w. First run 'daytona runner start' to start the runner daemon", err) + } + return err + } + + c, err := server.GetConfig() + if err != nil { + return err + } + + views.RenderInfoMessage("Starting the Daytona Runner daemon...") + err = daemon.Start(c.LogFile.Path, svcConfig) + if err != nil { + return err + } + views.RenderContainerLayout(views.GetBoldedInfoMessage("Daytona Runner daemon restarted successfully")) + return nil + }, +} diff --git a/pkg/cmd/runner/runner.go b/pkg/cmd/runner/runner.go new file mode 100644 index 0000000000..c6c9f4d51b --- /dev/null +++ b/pkg/cmd/runner/runner.go @@ -0,0 +1,29 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package runner + +import ( + "github.com/daytonaio/daytona/internal/util" + "github.com/spf13/cobra" +) + +var RunnerCmd = &cobra.Command{ + Use: "runner", + Short: "Manage the runner", + Args: cobra.NoArgs, + GroupID: util.RUNNER_GROUP, + Aliases: []string{"runners"}, +} + +func init() { + RunnerCmd.AddCommand(configCmd) + RunnerCmd.AddCommand(configureCmd) + RunnerCmd.AddCommand(startCmd) + RunnerCmd.AddCommand(serveCmd) + RunnerCmd.AddCommand(daemonServeCmd) + RunnerCmd.AddCommand(stopCmd) + RunnerCmd.AddCommand(restartCmd) + RunnerCmd.AddCommand(logsCmd) + RunnerCmd.AddCommand(purgeCmd) +} diff --git a/pkg/cmd/runner/serve.go b/pkg/cmd/runner/serve.go new file mode 100644 index 0000000000..178e534cd9 --- /dev/null +++ b/pkg/cmd/runner/serve.go @@ -0,0 +1,92 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package runner + +import ( + "context" + "io" + "os" + + "github.com/daytonaio/daytona/internal" + apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" + "github.com/daytonaio/daytona/pkg/cmd/bootstrap" + "github.com/daytonaio/daytona/pkg/posthogservice" + "github.com/daytonaio/daytona/pkg/runner" + "github.com/daytonaio/daytona/pkg/telemetry" + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" +) + +var daemonServeCmd = &cobra.Command{ + Use: "daemon-serve", + Short: "Used by the daemon to start the Daytona Runner", + Args: cobra.NoArgs, + Hidden: true, + RunE: serveCmd.RunE, +} + +var serveCmd = &cobra.Command{ + Use: "serve", + Short: "Starts the runner in the foreground", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.Background() + + if log.GetLevel() < log.InfoLevel { + log.SetLevel(log.InfoLevel) + } + + runnerConfig, err := runner.GetConfig() + if err != nil { + return err + } + + runnerConfigDir, err := runner.GetConfigDir() + if err != nil { + return err + } + + telemetryService := posthogservice.NewTelemetryService(posthogservice.PosthogServiceConfig{ + ApiKey: internal.PosthogApiKey, + Endpoint: internal.PosthogEndpoint, + Version: internal.Version, + Source: telemetry.RUNNER_SOURCE, + }) + + apiClient, err := apiclient_util.GetRunnerApiClient(runnerConfig.ServerApiUrl, runnerConfig.ServerApiKey, runnerConfig.ClientId, runnerConfig.TelemetryEnabled) + if err != nil { + return err + } + + serverConfig, _, err := apiClient.ServerAPI.GetConfig(ctx).Execute() + if err != nil { + return err + } + + var runnerLogWriter io.Writer + + if runnerConfig.LogFile != nil { + logFile, err := os.OpenFile(runnerConfig.LogFile.Path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + if err != nil { + return err + } + defer logFile.Close() + runnerLogWriter = logFile + } + + runner, err := bootstrap.GetRemoteRunner(bootstrap.RemoteRunnerParams{ + ApiClient: apiClient, + ServerConfig: serverConfig, + RunnerConfig: runnerConfig, + ConfigDir: runnerConfigDir, + LogWriter: runnerLogWriter, + TelemetryService: telemetryService, + }) + if err != nil { + return err + } + + return runner.Start(ctx) + }, +} diff --git a/pkg/cmd/runner/start.go b/pkg/cmd/runner/start.go new file mode 100644 index 0000000000..695e2cee68 --- /dev/null +++ b/pkg/cmd/runner/start.go @@ -0,0 +1,87 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package runner + +import ( + "context" + "fmt" + "os" + "runtime" + "time" + + apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" + "github.com/daytonaio/daytona/pkg/cmd/common/daemon" + "github.com/daytonaio/daytona/pkg/runner" + "github.com/daytonaio/daytona/pkg/views" + "github.com/kardianos/service" + "github.com/spf13/cobra" + + log "github.com/sirupsen/logrus" +) + +var svcConfig = &service.Config{ + Name: "DaytonaRunnerDaemon", + DisplayName: "Daytona Runner", + Description: "Daytona Runner daemon.", + Arguments: []string{"runner", "daemon-serve"}, +} + +var startCmd = &cobra.Command{ + Use: "start", + Short: "Starts the runner", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + if log.GetLevel() < log.InfoLevel { + // for now, force the log level to info when running the server + log.SetLevel(log.InfoLevel) + } + + c, err := runner.GetConfig() + if err != nil { + return err + } + + if c.ServerApiUrl == "" || c.ServerApiKey == "" { + views.RenderInfoMessage("Configure the runner by using 'daytona runner configure' before starting it.") + return nil + } + + views.RenderInfoMessageBold("Starting the Daytona Runner daemon...") + + err = daemon.Start(c.LogFile.Path, svcConfig) + if err != nil { + return err + } + + err = checkServerConnection(*c) + if err != nil { + return err + } + + switch runtime.GOOS { + case "linux": + fmt.Printf("Use `loginctl enable-linger %s` to allow the service to run after logging out.\n", os.Getenv("USER")) + } + return nil + }, +} + +func checkServerConnection(c runner.Config) error { + apiClient, err := apiclient_util.GetRunnerApiClient(c.ServerApiUrl, c.ServerApiKey, c.ClientId, c.TelemetryEnabled) + if err != nil { + return err + } + + for i := 0; i < 30; i++ { + time.Sleep(1 * time.Second) + _, _, err = apiClient.DefaultAPI.HealthCheck(context.Background()).Execute() + if err != nil { + continue + } + + return nil + } + + return err +} diff --git a/pkg/cmd/runner/stop.go b/pkg/cmd/runner/stop.go new file mode 100644 index 0000000000..f928d007bf --- /dev/null +++ b/pkg/cmd/runner/stop.go @@ -0,0 +1,28 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package runner + +import ( + "errors" + "fmt" + + "github.com/daytonaio/daytona/pkg/cmd/common/daemon" + "github.com/daytonaio/daytona/pkg/views" + "github.com/spf13/cobra" +) + +var stopCmd = &cobra.Command{ + Use: "stop", + Short: "Stops the runner", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + views.RenderInfoMessageBold("Stopping the Daytona Runner daemon...") + err := daemon.Stop(svcConfig) + if errors.Is(err, daemon.ErrDaemonNotInstalled) { + return fmt.Errorf("%w. First run 'daytona runner start' to start the runner daemon", err) + } + + return err + }, +} diff --git a/pkg/cmd/server/configure.go b/pkg/cmd/server/configure.go index 17be48ed01..8a7555625b 100644 --- a/pkg/cmd/server/configure.go +++ b/pkg/cmd/server/configure.go @@ -26,17 +26,12 @@ var configureCmd = &cobra.Command{ return apiclient.HandleErrorResponse(res, err) } - containerRegistries, res, err := apiClient.ContainerRegistryAPI.ListContainerRegistries(context.Background()).Execute() - if err != nil { - return apiclient.HandleErrorResponse(res, err) - } - - apiServerConfig, err = server_view.ConfigurationForm(apiServerConfig, containerRegistries) + apiServerConfig, err = server_view.ConfigurationForm(apiServerConfig) if err != nil { return err } - _, res, err = apiClient.ServerAPI.SetConfig(context.Background()).Config(*apiServerConfig).Execute() + _, res, err = apiClient.ServerAPI.SaveConfig(context.Background()).Config(*apiServerConfig).Execute() if err != nil { return apiclient.HandleErrorResponse(res, err) } diff --git a/pkg/cmd/server/logs/list.go b/pkg/cmd/server/logs/list.go index 967002ee31..cbaa62d6ad 100644 --- a/pkg/cmd/server/logs/list.go +++ b/pkg/cmd/server/logs/list.go @@ -7,14 +7,15 @@ import ( "context" apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" + "github.com/daytonaio/daytona/pkg/cmd/common" "github.com/daytonaio/daytona/pkg/views/server" "github.com/spf13/cobra" ) var listCmd = &cobra.Command{ Use: "list", - Aliases: []string{"ls"}, Short: "Lists Daytona Server Log Files", + Aliases: common.GetAliases("list"), RunE: func(cmd *cobra.Command, args []string) error { ctx := context.Background() diff --git a/pkg/cmd/server/logs/logs.go b/pkg/cmd/server/logs/logs.go index 92b2facf0f..658d0c2018 100644 --- a/pkg/cmd/server/logs/logs.go +++ b/pkg/cmd/server/logs/logs.go @@ -17,6 +17,8 @@ import ( "github.com/daytonaio/daytona/internal/constants" "github.com/daytonaio/daytona/internal/util" apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" + "github.com/daytonaio/daytona/pkg/cmd/common" + "github.com/daytonaio/daytona/pkg/logs" "github.com/daytonaio/daytona/pkg/server" "github.com/daytonaio/daytona/pkg/views" "github.com/daytonaio/daytona/pkg/views/server/selection" @@ -37,8 +39,9 @@ func init() { } var LogsCmd = &cobra.Command{ - Use: "logs", - Short: "Output Daytona Server logs", + Use: "logs", + Short: "Output Daytona Server logs", + Aliases: common.GetAliases("logs"), RunE: func(cmd *cobra.Command, args []string) error { ctx := context.Background() @@ -101,7 +104,7 @@ func readRemoteServerLogFile(ctx context.Context, activeProfile config.Profile, query += fmt.Sprintf("file=%s", filepath.Base(fileFlag)) } - ws, res, err := apiclient_util.GetWebsocketConn(context.Background(), "/log/server", &activeProfile, &query) + ws, res, err := util.GetWebsocketConn(context.Background(), "/log/server", activeProfile.Api.Url, activeProfile.Api.Key, &query) if res.StatusCode == http.StatusNotFound { return apiclient_util.HandleErrorResponse(res, err) } @@ -177,7 +180,7 @@ func readLocalServerLogFile() error { var reader io.Reader if regexp.MustCompile(constants.ZIP_LOG_FILE_NAME_SUFFIX_PATTERN).MatchString(logFile) { - reader, err = util.ReadCompressedFile(logFile) + reader, err = logs.ReadCompressedFile(logFile) } else { reader, err = os.Open(logFile) } @@ -188,7 +191,7 @@ func readLocalServerLogFile() error { msgChan := make(chan []byte) errChan := make(chan error) - go util.ReadLog(context.Background(), reader, followFlag, msgChan, errChan) + go logs.ReadLog(context.Background(), reader, followFlag, msgChan, errChan) for { select { diff --git a/pkg/cmd/server/restart.go b/pkg/cmd/server/restart.go index 3234a02145..f46ac28b82 100644 --- a/pkg/cmd/server/restart.go +++ b/pkg/cmd/server/restart.go @@ -4,9 +4,12 @@ package server import ( + "errors" + "fmt" + "github.com/spf13/cobra" - "github.com/daytonaio/daytona/pkg/cmd/server/daemon" + "github.com/daytonaio/daytona/pkg/cmd/common/daemon" "github.com/daytonaio/daytona/pkg/server" "github.com/daytonaio/daytona/pkg/views" ) @@ -16,8 +19,11 @@ var restartCmd = &cobra.Command{ Short: "Restarts the Daytona Server daemon", RunE: func(cmd *cobra.Command, args []string) error { views.RenderInfoMessage("Stopping the Daytona Server daemon...") - err := daemon.Stop() + err := daemon.Stop(svcConfig) if err != nil { + if errors.Is(err, daemon.ErrDaemonNotInstalled) { + return fmt.Errorf("%w. First run 'daytona server' to start the server daemon", err) + } return err } @@ -27,7 +33,7 @@ var restartCmd = &cobra.Command{ } views.RenderInfoMessage("Starting the Daytona Server daemon...") - err = daemon.Start(c.LogFile.Path) + err = daemon.Start(c.LogFile.Path, svcConfig) if err != nil { return err } diff --git a/pkg/cmd/server/runner/create.go b/pkg/cmd/server/runner/create.go new file mode 100644 index 0000000000..aac7aebc08 --- /dev/null +++ b/pkg/cmd/server/runner/create.go @@ -0,0 +1,83 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package runner + +import ( + "context" + + "github.com/daytonaio/daytona/cmd/daytona/config" + "github.com/daytonaio/daytona/internal/util" + apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" + "github.com/daytonaio/daytona/pkg/apiclient" + "github.com/daytonaio/daytona/pkg/cmd/common" + "github.com/daytonaio/daytona/pkg/views/server/runner" + "github.com/docker/docker/pkg/stringid" + + "github.com/spf13/cobra" +) + +var createCmd = &cobra.Command{ + Use: "create", + Short: "Create a runner", + Args: cobra.NoArgs, + Aliases: common.GetAliases("create"), + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.Background() + + c, err := config.GetConfig() + if err != nil { + return err + } + + apiClient, err := apiclient_util.GetApiClient(nil) + if err != nil { + return err + } + + runnerList, res, err := apiClient.RunnerAPI.ListRunners(ctx).Execute() + if err != nil { + return apiclient_util.HandleErrorResponse(res, err) + } + + existingRunnerNames := util.ArrayMap(runnerList, func(r apiclient.RunnerDTO) string { + return r.Name + }) + + name := nameFlag + + if name == "" { + err = runner.RunnerCreationView(&name, existingRunnerNames) + if err != nil { + return err + } + } + + id := stringid.GenerateRandomID() + id = stringid.TruncateID(id) + + runnerDto, res, err := apiClient.RunnerAPI.CreateRunner(ctx).Runner(apiclient.CreateRunnerDTO{ + Id: id, + Name: name, + }).Execute() + if err != nil { + return apiclient_util.HandleErrorResponse(res, err) + } + + apiServerConfig, res, err := apiClient.ServerAPI.GetConfig(context.Background()).Execute() + if err != nil { + return apiclient_util.HandleErrorResponse(res, err) + } + + apiUrl := util.GetFrpcApiUrl(apiServerConfig.Frps.Protocol, apiServerConfig.Id, apiServerConfig.Frps.Domain) + runner.Notify(runnerDto, apiUrl, c.Id, !c.TelemetryEnabled) + + return nil + }, +} + +var nameFlag string + +func init() { + createCmd.Flags().StringVarP(&nameFlag, "name", "n", "", "Runner name") +} diff --git a/pkg/cmd/server/runner/delete.go b/pkg/cmd/server/runner/delete.go new file mode 100644 index 0000000000..4da7271351 --- /dev/null +++ b/pkg/cmd/server/runner/delete.go @@ -0,0 +1,109 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package runner + +import ( + "context" + "errors" + "fmt" + + "github.com/charmbracelet/huh" + "github.com/daytonaio/daytona/cmd/daytona/config" + apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" + cmd_common "github.com/daytonaio/daytona/pkg/cmd/common" + "github.com/daytonaio/daytona/pkg/common" + "github.com/daytonaio/daytona/pkg/views" + runner "github.com/daytonaio/daytona/pkg/views/server/runner/selection" + views_util "github.com/daytonaio/daytona/pkg/views/util" + + "github.com/spf13/cobra" +) + +var deleteCmd = &cobra.Command{ + Use: "delete [RUNNER]", + Short: "Delete a runner", + Args: cobra.RangeArgs(0, 1), + Aliases: cmd_common.GetAliases("delete"), + RunE: func(cmd *cobra.Command, args []string) error { + + var selectedRunnerId string + + ctx := context.Background() + apiClient, err := apiclient_util.GetApiClient(nil) + if err != nil { + return err + } + + c, err := config.GetConfig() + if err != nil { + return err + } + + if len(args) == 0 { + activeProfile, err := c.GetActiveProfile() + if err != nil { + return err + } + + runners, res, err := apiClient.RunnerAPI.ListRunners(ctx).Execute() + if err != nil { + return apiclient_util.HandleErrorResponse(res, err) + } + + if len(runners) == 0 { + views_util.NotifyEmptyRunnerList(false) + return nil + } + + selectedRunner, err := runner.GetRunnerFromPrompt(runners, activeProfile.Name, "Delete") + if err != nil { + if common.IsCtrlCAbort(err) { + return nil + } else { + return err + } + } + + selectedRunnerId = selectedRunner.Id + } else { + selectedRunnerId = args[0] + } + + if selectedRunnerId == common.LOCAL_RUNNER_ID { + return errors.New("to disable the local runner, use the 'daytona server configure' form") + } + + var confirm bool + + if !yesFlag { + form := huh.NewForm( + huh.NewGroup( + huh.NewConfirm(). + Title(fmt.Sprintf("Delete runner %s?", selectedRunnerId)). + Description("It is recommended that you remove all target configs, targets and workspaces associated with it."). + Value(&confirm), + ), + ).WithTheme(views.GetCustomTheme()) + + err := form.Run() + if err != nil { + return err + } + } + + res, err := apiClient.RunnerAPI.DeleteRunner(ctx, selectedRunnerId).Execute() + if err != nil { + return apiclient_util.HandleErrorResponse(res, err) + } + + views.RenderInfoMessageBold(fmt.Sprintf("Runner %s deleted successfully", selectedRunnerId)) + return nil + }, +} + +var yesFlag bool + +func init() { + deleteCmd.Flags().BoolVarP(&yesFlag, "yes", "y", false, "Confirm deletion without prompt") +} diff --git a/pkg/cmd/server/runner/list.go b/pkg/cmd/server/runner/list.go new file mode 100644 index 0000000000..099a9de076 --- /dev/null +++ b/pkg/cmd/server/runner/list.go @@ -0,0 +1,47 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package runner + +import ( + "context" + + "github.com/daytonaio/daytona/pkg/cmd/common" + "github.com/daytonaio/daytona/pkg/cmd/format" + "github.com/daytonaio/daytona/pkg/views/server/runner/list" + + apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" + "github.com/spf13/cobra" +) + +var listCmd = &cobra.Command{ + Use: "list", + Short: "List runners", + Aliases: common.GetAliases("list"), + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.Background() + + apiClient, err := apiclient_util.GetApiClient(nil) + if err != nil { + return err + } + + runners, res, err := apiClient.RunnerAPI.ListRunners(ctx).Execute() + if err != nil { + return apiclient_util.HandleErrorResponse(res, err) + } + + if format.FormatFlag != "" { + formattedData := format.NewFormatter(runners) + formattedData.Print() + return nil + } + + list.ListRunners(runners) + return nil + }, +} + +func init() { + format.RegisterFormatFlag(listCmd) +} diff --git a/pkg/cmd/server/runner/logs.go b/pkg/cmd/server/runner/logs.go new file mode 100644 index 0000000000..960ad3f1a2 --- /dev/null +++ b/pkg/cmd/server/runner/logs.go @@ -0,0 +1,100 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package runner + +import ( + "context" + "fmt" + "net/http" + + "github.com/daytonaio/daytona/cmd/daytona/config" + "github.com/daytonaio/daytona/internal/util" + apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" + cmd_common "github.com/daytonaio/daytona/pkg/cmd/common" + "github.com/daytonaio/daytona/pkg/common" + runner "github.com/daytonaio/daytona/pkg/views/server/runner/selection" + views_util "github.com/daytonaio/daytona/pkg/views/util" + + "github.com/spf13/cobra" +) + +var followFlag bool + +var logsCmd = &cobra.Command{ + Use: "logs [RUNNER_ID]", + Short: "View runner logs", + Args: cobra.MaximumNArgs(1), + Aliases: cmd_common.GetAliases("logs"), + RunE: func(cmd *cobra.Command, args []string) error { + var selectedRunnerId string + ctx := context.Background() + + apiClient, err := apiclient_util.GetApiClient(nil) + if err != nil { + return err + } + + c, err := config.GetConfig() + if err != nil { + return err + } + + activeProfile, err := c.GetActiveProfile() + if err != nil { + return err + } + + if len(args) == 0 { + activeProfile, err := c.GetActiveProfile() + if err != nil { + return err + } + + runners, res, err := apiClient.RunnerAPI.ListRunners(ctx).Execute() + if err != nil { + return apiclient_util.HandleErrorResponse(res, err) + } + + if len(runners) == 0 { + views_util.NotifyEmptyRunnerList(false) + return nil + } + + selectedRunner, err := runner.GetRunnerFromPrompt(runners, activeProfile.Name, "View Logs") + if err != nil { + if common.IsCtrlCAbort(err) { + return nil + } else { + return err + } + } + + selectedRunnerId = selectedRunner.Name + } else { + selectedRunnerId = args[0] + } + + runner, res, err := apiClient.RunnerAPI.FindRunner(ctx, selectedRunnerId).Execute() + if err != nil { + if res.StatusCode == http.StatusNotFound { + return fmt.Errorf("runner %s not found", selectedRunnerId) + } + return apiclient_util.HandleErrorResponse(res, err) + } + + cmd_common.ReadRunnerLogs(ctx, cmd_common.ReadLogParams{ + Id: runner.Id, + Label: &runner.Name, + ServerUrl: activeProfile.Api.Url, + ApiKey: activeProfile.Api.Key, + Index: util.Pointer(0), + Follow: &followFlag, + }) + return nil + }, +} + +func init() { + logsCmd.Flags().BoolVarP(&followFlag, "follow", "f", false, "Follow logs") +} diff --git a/pkg/cmd/server/runner/runner.go b/pkg/cmd/server/runner/runner.go new file mode 100644 index 0000000000..7e0b803e72 --- /dev/null +++ b/pkg/cmd/server/runner/runner.go @@ -0,0 +1,20 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package runner + +import ( + "github.com/spf13/cobra" +) + +var RunnerCmd = &cobra.Command{ + Use: "runner", + Short: "Manage runners", +} + +func init() { + RunnerCmd.AddCommand(logsCmd) + RunnerCmd.AddCommand(listCmd) + RunnerCmd.AddCommand(createCmd) + RunnerCmd.AddCommand(deleteCmd) +} diff --git a/pkg/cmd/server/serve.go b/pkg/cmd/server/serve.go index 3fdf0e4f72..e101fbfd24 100644 --- a/pkg/cmd/server/serve.go +++ b/pkg/cmd/server/serve.go @@ -4,39 +4,29 @@ package server import ( + "context" "errors" "fmt" - "net/url" "os" "os/signal" "path/filepath" - "strings" "time" "github.com/daytonaio/daytona/cmd/daytona/config" "github.com/daytonaio/daytona/internal" - "github.com/daytonaio/daytona/internal/constants" "github.com/daytonaio/daytona/internal/util" "github.com/daytonaio/daytona/pkg/api" - "github.com/daytonaio/daytona/pkg/apikey" - "github.com/daytonaio/daytona/pkg/build" - "github.com/daytonaio/daytona/pkg/containerregistry" - "github.com/daytonaio/daytona/pkg/db" + "github.com/daytonaio/daytona/pkg/cmd/bootstrap" + "github.com/daytonaio/daytona/pkg/common" "github.com/daytonaio/daytona/pkg/logs" + "github.com/daytonaio/daytona/pkg/models" "github.com/daytonaio/daytona/pkg/posthogservice" - "github.com/daytonaio/daytona/pkg/provider/manager" - "github.com/daytonaio/daytona/pkg/provisioner" + "github.com/daytonaio/daytona/pkg/runner" "github.com/daytonaio/daytona/pkg/server" - "github.com/daytonaio/daytona/pkg/server/apikeys" - "github.com/daytonaio/daytona/pkg/server/builds" - "github.com/daytonaio/daytona/pkg/server/containerregistries" - "github.com/daytonaio/daytona/pkg/server/gitproviders" "github.com/daytonaio/daytona/pkg/server/headscale" - "github.com/daytonaio/daytona/pkg/server/profiledata" - "github.com/daytonaio/daytona/pkg/server/projectconfig" - "github.com/daytonaio/daytona/pkg/server/providertargets" "github.com/daytonaio/daytona/pkg/server/registry" - "github.com/daytonaio/daytona/pkg/server/workspaces" + "github.com/daytonaio/daytona/pkg/services" + "github.com/daytonaio/daytona/pkg/stores" "github.com/daytonaio/daytona/pkg/telemetry" "github.com/daytonaio/daytona/pkg/views" started_view "github.com/daytonaio/daytona/pkg/views/server/started" @@ -60,7 +50,7 @@ var ServeCmd = &cobra.Command{ Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { if os.Getenv("USER") == "root" { - views.RenderInfoMessageBold("Running the server as root is not recommended because\nDaytona will not be able to remap project directory ownership.\nPlease run the server as a non-root user.") + views.RenderInfoMessageBold("Running the server as root is not recommended because\nDaytona will not be able to remap workspace directory ownership.\nPlease run the server as a non-root user.") } if log.GetLevel() < log.InfoLevel { @@ -78,10 +68,16 @@ var ServeCmd = &cobra.Command{ return err } + cliConfig, err := config.GetConfig() + if err != nil { + return err + } + telemetryService := posthogservice.NewTelemetryService(posthogservice.PosthogServiceConfig{ ApiKey: internal.PosthogApiKey, Endpoint: internal.PosthogEndpoint, Version: internal.Version, + Source: telemetry.SERVER_SOURCE, }) apiServer := api.NewApiServer(api.ApiServerConfig{ @@ -92,22 +88,7 @@ var ServeCmd = &cobra.Command{ Frps: c.Frps, }) - server, err := GetInstance(c, configDir, internal.Version, telemetryService) - if err != nil { - return err - } - - buildRunnerConfig, err := build.GetConfig() - if err != nil { - return err - } - - buildRunner, err := GetBuildRunner(c, buildRunnerConfig, telemetryService) - if err != nil { - return err - } - - err = buildRunner.Start() + server, err := bootstrap.GetInstance(c, configDir, internal.Version, telemetryService) if err != nil { return err } @@ -139,7 +120,7 @@ var ServeCmd = &cobra.Command{ log.Info("Starting local container registry...") localContainerRegistryErrChan <- server.LocalContainerRegistry.Start() } else { - localContainerRegistryErrChan <- registry.RemoveRegistryContainer() + localContainerRegistryErrChan <- registry.DeleteRegistryContainer() } }() @@ -147,16 +128,30 @@ var ServeCmd = &cobra.Command{ case <-headscaleServerStartedChan: log.Info("Headscale server started") go func() { - headscaleServerErrChan <- server.TailscaleServer.Connect() + headscaleServerErrChan <- server.TailscaleServer.Connect(headscale.HEADSCALE_USERNAME) }() case err := <-headscaleServerErrChan: return err } - err = server.Start() - if err != nil { - return err - } + localRunnerErrChan := make(chan error) + + go func() { + if c.LocalRunnerDisabled != nil && *c.LocalRunnerDisabled { + err = handleDisabledLocalRunner() + if err != nil { + localRunnerErrChan <- err + } + return + } + + localRunnerErrChan <- startLocalRunner(bootstrap.LocalRunnerParams{ + ServerConfig: c, + RunnerConfig: GetLocalRunnerConfig(filepath.Join(configDir, "local-runner"), cliConfig.TelemetryEnabled, cliConfig.Id), + ConfigDir: configDir, + TelemetryService: telemetryService, + }) + }() err = waitForApiServerToStart(apiServer) if err != nil { @@ -168,6 +163,13 @@ var ServeCmd = &cobra.Command{ log.Errorf("Failed to start local container registry: %v\nBuilds may not work properly.\nRestart the server to restart the registry.", err) } + if c.LocalRunnerDisabled != nil && !*c.LocalRunnerDisabled { + err = awaitLocalRunnerStarted() + if err != nil { + localRunnerErrChan <- err + } + } + printServerStartedMessage(c, false) err = ensureDefaultProfile(server, c.ApiPort) @@ -179,6 +181,8 @@ var ServeCmd = &cobra.Command{ signal.Notify(interruptChannel, os.Interrupt) select { + case err := <-localRunnerErrChan: + return err case err := <-apiServerErrChan: return err case err := <-headscaleServerErrChan: @@ -191,290 +195,6 @@ var ServeCmd = &cobra.Command{ }, } -func GetInstance(c *server.Config, configDir string, version string, telemetryService telemetry.TelemetryService) (*server.Server, error) { - wsLogsDir, err := server.GetWorkspaceLogsDir(configDir) - if err != nil { - return nil, err - } - buildLogsDir, err := build.GetBuildLogsDir() - if err != nil { - return nil, err - } - loggerFactory := logs.NewLoggerFactory(&wsLogsDir, &buildLogsDir) - - dbPath, err := getDbPath() - if err != nil { - return nil, err - } - - dbConnection := db.GetSQLiteConnection(dbPath) - - apiKeyStore, err := db.NewApiKeyStore(dbConnection) - if err != nil { - return nil, err - } - containerRegistryStore, err := db.NewContainerRegistryStore(dbConnection) - if err != nil { - return nil, err - } - buildStore, err := db.NewBuildStore(dbConnection) - if err != nil { - return nil, err - } - projectConfigStore, err := db.NewProjectConfigStore(dbConnection) - if err != nil { - return nil, err - } - gitProviderConfigStore, err := db.NewGitProviderConfigStore(dbConnection) - if err != nil { - return nil, err - } - providerTargetStore, err := db.NewProviderTargetStore(dbConnection) - if err != nil { - return nil, err - } - workspaceStore, err := db.NewWorkspaceStore(dbConnection) - if err != nil { - return nil, err - } - profileDataStore, err := db.NewProfileDataStore(dbConnection) - if err != nil { - return nil, err - } - - headscaleServer := headscale.NewHeadscaleServer(&headscale.HeadscaleServerConfig{ - ServerId: c.Id, - FrpsDomain: c.Frps.Domain, - FrpsProtocol: c.Frps.Protocol, - HeadscalePort: c.HeadscalePort, - ConfigDir: filepath.Join(configDir, "headscale"), - Frps: c.Frps, - }) - err = headscaleServer.Init() - if err != nil { - return nil, err - } - - containerRegistryService := containerregistries.NewContainerRegistryService(containerregistries.ContainerRegistryServiceConfig{ - Store: containerRegistryStore, - }) - - buildService := builds.NewBuildService(builds.BuildServiceConfig{ - BuildStore: buildStore, - LoggerFactory: loggerFactory, - }) - - gitProviderService := gitproviders.NewGitProviderService(gitproviders.GitProviderServiceConfig{ - ConfigStore: gitProviderConfigStore, - ProjectConfigStore: projectConfigStore, - }) - - prebuildWebhookEndpoint := fmt.Sprintf("%s%s", util.GetFrpcApiUrl(c.Frps.Protocol, c.Id, c.Frps.Domain), constants.WEBHOOK_EVENT_ROUTE) - - projectConfigService := projectconfig.NewProjectConfigService(projectconfig.ProjectConfigServiceConfig{ - PrebuildWebhookEndpoint: prebuildWebhookEndpoint, - ConfigStore: projectConfigStore, - BuildService: buildService, - GitProviderService: gitProviderService, - }) - - err = projectConfigService.StartRetentionPoller() - if err != nil { - return nil, err - } - - var localContainerRegistry server.ILocalContainerRegistry - - if c.BuilderRegistryServer != "local" { - _, err := containerRegistryService.Find(c.BuilderRegistryServer) - if err != nil { - log.Errorf("Failed to find container registry credentials for builder registry server %s\n", c.BuilderRegistryServer) - log.Errorf("Defaulting to local container registry. To use %s as the builder registry, add credentials for the registry server with 'daytona container-registry set' and restart the server\n", c.BuilderRegistryServer) - c.BuilderRegistryServer = "local" - } - } - - if c.BuilderRegistryServer == "local" { - cr, err := containerRegistryService.FindByImageName(c.LocalBuilderRegistryImage) - if err != nil && !containerregistry.IsContainerRegistryNotFound(err) { - return nil, err - } - - localContainerRegistry = registry.NewLocalContainerRegistry(®istry.LocalContainerRegistryConfig{ - DataPath: filepath.Join(configDir, "registry"), - Port: c.LocalBuilderRegistryPort, - Image: c.LocalBuilderRegistryImage, - ContainerRegistry: cr, - Logger: log.StandardLogger().Writer(), - Frps: c.Frps, - ServerId: c.Id, - }) - c.BuilderRegistryServer = util.GetFrpcRegistryDomain(c.Id, c.Frps.Domain) - } - - providerTargetService := providertargets.NewProviderTargetService(providertargets.ProviderTargetServiceConfig{ - TargetStore: providerTargetStore, - }) - - apiKeyService := apikeys.NewApiKeyService(apikeys.ApiKeyServiceConfig{ - ApiKeyStore: apiKeyStore, - }) - - headscaleUrl := util.GetFrpcHeadscaleUrl(c.Frps.Protocol, c.Id, c.Frps.Domain) - - providerManager := manager.NewProviderManager(manager.ProviderManagerConfig{ - LogsDir: wsLogsDir, - ProviderTargetService: providerTargetService, - ApiUrl: util.GetFrpcApiUrl(c.Frps.Protocol, c.Id, c.Frps.Domain), - DaytonaDownloadUrl: getDaytonaScriptUrl(c), - ServerUrl: headscaleUrl, - ServerVersion: version, - RegistryUrl: c.RegistryUrl, - BaseDir: c.ProvidersDir, - CreateProviderNetworkKey: func(providerName string) (string, error) { - return headscaleServer.CreateAuthKey() - }, - ServerPort: c.HeadscalePort, - ApiPort: c.ApiPort, - }) - - provisioner := provisioner.NewProvisioner(provisioner.ProvisionerConfig{ - ProviderManager: providerManager, - }) - - workspaceService := workspaces.NewWorkspaceService(workspaces.WorkspaceServiceConfig{ - WorkspaceStore: workspaceStore, - TargetStore: providerTargetStore, - ApiKeyService: apiKeyService, - GitProviderService: gitProviderService, - ContainerRegistryService: containerRegistryService, - BuilderImage: c.BuilderImage, - BuildService: buildService, - ProjectConfigService: projectConfigService, - ServerApiUrl: util.GetFrpcApiUrl(c.Frps.Protocol, c.Id, c.Frps.Domain), - ServerVersion: version, - ServerUrl: headscaleUrl, - DefaultProjectImage: c.DefaultProjectImage, - DefaultProjectUser: c.DefaultProjectUser, - Provisioner: provisioner, - LoggerFactory: loggerFactory, - TelemetryService: telemetryService, - }) - - profileDataService := profiledata.NewProfileDataService(profiledata.ProfileDataServiceConfig{ - ProfileDataStore: profileDataStore, - }) - - s := server.GetInstance(&server.ServerInstanceConfig{ - Config: *c, - Version: version, - TailscaleServer: headscaleServer, - ProviderTargetService: providerTargetService, - ContainerRegistryService: containerRegistryService, - BuildService: buildService, - ProjectConfigService: projectConfigService, - LocalContainerRegistry: localContainerRegistry, - ApiKeyService: apiKeyService, - WorkspaceService: workspaceService, - GitProviderService: gitProviderService, - ProviderManager: providerManager, - ProfileDataService: profileDataService, - TelemetryService: telemetryService, - }) - - return s, s.Initialize() -} - -func GetBuildRunner(c *server.Config, buildRunnerConfig *build.Config, telemetryService telemetry.TelemetryService) (*build.BuildRunner, error) { - logsDir, err := build.GetBuildLogsDir() - if err != nil { - return nil, err - } - loggerFactory := logs.NewLoggerFactory(nil, &logsDir) - - dbPath, err := getDbPath() - if err != nil { - return nil, err - } - - dbConnection := db.GetSQLiteConnection(dbPath) - - gitProviderConfigStore, err := db.NewGitProviderConfigStore(dbConnection) - if err != nil { - return nil, err - } - - gitProviderService := gitproviders.NewGitProviderService(gitproviders.GitProviderServiceConfig{ - ConfigStore: gitProviderConfigStore, - }) - - buildStore, err := db.NewBuildStore(dbConnection) - if err != nil { - return nil, err - } - - buildImageNamespace := c.BuildImageNamespace - if buildImageNamespace != "" { - buildImageNamespace = fmt.Sprintf("/%s", buildImageNamespace) - } - buildImageNamespace = strings.TrimSuffix(buildImageNamespace, "/") - - containerRegistryStore, err := db.NewContainerRegistryStore(dbConnection) - if err != nil { - return nil, err - } - - containerRegistryService := containerregistries.NewContainerRegistryService(containerregistries.ContainerRegistryServiceConfig{ - Store: containerRegistryStore, - }) - - var buildImageCr *containerregistry.ContainerRegistry - - if c.BuilderRegistryServer != "local" { - buildImageCr, err = containerRegistryService.Find(c.BuilderRegistryServer) - if err != nil { - buildImageCr = &containerregistry.ContainerRegistry{ - Server: c.BuilderRegistryServer, - } - } - } - - cr, err := containerRegistryService.FindByImageName(c.BuilderImage) - if err != nil && !containerregistry.IsContainerRegistryNotFound(err) { - return nil, err - } - - configDir, err := config.GetConfigDir() - if err != nil { - return nil, err - } - - builderFactory := build.NewBuilderFactory(build.BuilderFactoryConfig{ - Image: c.BuilderImage, - ContainerRegistry: cr, - BuildImageContainerRegistry: buildImageCr, - BuildStore: buildStore, - BuildImageNamespace: buildImageNamespace, - LoggerFactory: loggerFactory, - DefaultProjectImage: c.DefaultProjectImage, - DefaultProjectUser: c.DefaultProjectUser, - }) - - return build.NewBuildRunner(build.BuildRunnerInstanceConfig{ - Interval: buildRunnerConfig.Interval, - Scheduler: build.NewCronScheduler(), - BuildRunnerId: buildRunnerConfig.Id, - ContainerRegistry: buildImageCr, - TelemetryEnabled: buildRunnerConfig.TelemetryEnabled, - GitProviderStore: gitProviderService, - BuildStore: buildStore, - BuilderFactory: builderFactory, - LoggerFactory: loggerFactory, - BasePath: filepath.Join(configDir, "builds"), - TelemetryService: telemetryService, - }), nil -} - func waitForApiServerToStart(apiServer *api.ApiServer) error { var err error for i := 0; i < 30; i++ { @@ -490,29 +210,10 @@ func waitForApiServerToStart(apiServer *api.ApiServer) error { return err } -func getDaytonaScriptUrl(config *server.Config) string { - url, _ := url.JoinPath(util.GetFrpcApiUrl(config.Frps.Protocol, config.Id, config.Frps.Domain), "binary", "script") - return url -} - func printServerStartedMessage(c *server.Config, runAsDaemon bool) { started_view.Render(c.ApiPort, util.GetFrpcApiUrl(c.Frps.Protocol, c.Id, c.Frps.Domain), runAsDaemon) } -func getDbPath() (string, error) { - configDir, err := config.GetConfigDir() - if err != nil { - return "", err - } - - err = os.MkdirAll(configDir, 0755) - if err != nil { - return "", err - } - - return filepath.Join(configDir, "db"), nil -} - func ensureDefaultProfile(server *server.Server, apiPort uint32) error { existingConfig, err := config.GetConfig() if err != nil { @@ -529,7 +230,7 @@ func ensureDefaultProfile(server *server.Server, apiPort uint32) error { } } - apiKey, err := server.ApiKeyService.Generate(apikey.ApiKeyTypeClient, "default") + apiKey, err := server.ApiKeyService.Create(context.Background(), models.ApiKeyTypeClient, "default") if err != nil { return err } @@ -543,3 +244,81 @@ func ensureDefaultProfile(server *server.Server, apiPort uint32) error { }, }) } + +func startLocalRunner(params bootstrap.LocalRunnerParams) error { + runnerService := server.GetInstance(nil).RunnerService + + _, err := runnerService.Find(context.Background(), common.LOCAL_RUNNER_ID) + if err != nil { + if stores.IsRunnerNotFound(err) { + _, err := runnerService.Create(context.Background(), services.CreateRunnerDTO{ + Id: common.LOCAL_RUNNER_ID, + Name: common.LOCAL_RUNNER_ID, + }) + if err != nil { + return err + } + } else { + return err + } + } + + runner, err := bootstrap.GetLocalRunner(params) + if err != nil { + return err + } + + return runner.Start(context.Background()) +} + +func GetLocalRunnerConfig(configDir string, telemetryEnabled bool, clientId string) *runner.Config { + providersDir := filepath.Join(configDir, "providers") + logFilePath := filepath.Join(configDir, "runner.log") + + return &runner.Config{ + Id: common.LOCAL_RUNNER_ID, + Name: common.LOCAL_RUNNER_ID, + ProvidersDir: providersDir, + LogFile: logs.GetDefaultLogFileConfig(logFilePath), + TelemetryEnabled: telemetryEnabled, + ClientId: clientId, + } +} + +func awaitLocalRunnerStarted() error { + server := server.GetInstance(nil) + startTime := time.Now() + + for { + r, err := server.RunnerService.Find(context.Background(), common.LOCAL_RUNNER_ID) + if err != nil { + return err + } + + if r.Metadata.Uptime > 0 { + break + } + + if time.Since(startTime) > 10*time.Second { + log.Info("Waiting for runner ...") + startTime = time.Now() + } + + time.Sleep(1 * time.Second) + } + + return nil +} + +func handleDisabledLocalRunner() error { + runnerService := server.GetInstance(nil).RunnerService + + _, err := runnerService.Find(context.Background(), common.LOCAL_RUNNER_ID) + if err != nil { + if stores.IsRunnerNotFound(err) { + return nil + } + } + + return runnerService.Delete(context.Background(), common.LOCAL_RUNNER_ID) +} diff --git a/pkg/cmd/server/server.go b/pkg/cmd/server/server.go index ce3681c7e9..4e1815cd36 100644 --- a/pkg/cmd/server/server.go +++ b/pkg/cmd/server/server.go @@ -10,11 +10,13 @@ import ( "github.com/daytonaio/daytona/internal/util" "github.com/daytonaio/daytona/pkg/api" - "github.com/daytonaio/daytona/pkg/cmd/server/daemon" + "github.com/daytonaio/daytona/pkg/cmd/common/daemon" "github.com/daytonaio/daytona/pkg/cmd/server/logs" + "github.com/daytonaio/daytona/pkg/cmd/server/runner" "github.com/daytonaio/daytona/pkg/server" "github.com/daytonaio/daytona/pkg/views" view "github.com/daytonaio/daytona/pkg/views/server" + "github.com/kardianos/service" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -22,6 +24,13 @@ import ( var yesFlag bool +var svcConfig = &service.Config{ + Name: "DaytonaServerDaemon", + DisplayName: "Daytona Server", + Description: "Daytona Server daemon.", + Arguments: []string{"daemon-serve"}, +} + var ServerCmd = &cobra.Command{ Use: "server", Short: "Start the server process in daemon mode", @@ -53,7 +62,7 @@ var ServerCmd = &cobra.Command{ }) views.RenderInfoMessageBold("Starting the Daytona Server daemon...") - err = daemon.Start(c.LogFile.Path) + err = daemon.Start(c.LogFile.Path, svcConfig) if err != nil { return err } @@ -78,6 +87,7 @@ var startCmd = &cobra.Command{ } func init() { + ServerCmd.AddCommand(runner.RunnerCmd) ServerCmd.AddCommand(configureCmd) ServerCmd.AddCommand(configCmd) ServerCmd.AddCommand(logs.LogsCmd) diff --git a/pkg/cmd/server/stop.go b/pkg/cmd/server/stop.go index 12d9ca72ac..da9871ef01 100644 --- a/pkg/cmd/server/stop.go +++ b/pkg/cmd/server/stop.go @@ -4,9 +4,12 @@ package server import ( + "errors" + "fmt" + "github.com/spf13/cobra" - "github.com/daytonaio/daytona/pkg/cmd/server/daemon" + "github.com/daytonaio/daytona/pkg/cmd/common/daemon" "github.com/daytonaio/daytona/pkg/views" ) @@ -15,6 +18,11 @@ var stopCmd = &cobra.Command{ Short: "Stops the Daytona Server daemon", RunE: func(cmd *cobra.Command, args []string) error { views.RenderInfoMessageBold("Stopping the Daytona Server daemon...") - return daemon.Stop() + err := daemon.Stop(svcConfig) + if errors.Is(err, daemon.ErrDaemonNotInstalled) { + return fmt.Errorf("%w. First run 'daytona server' to start the server daemon", err) + } + + return err }, } diff --git a/pkg/cmd/target/create.go b/pkg/cmd/target/create.go new file mode 100644 index 0000000000..a0244a53b3 --- /dev/null +++ b/pkg/cmd/target/create.go @@ -0,0 +1,170 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package target + +import ( + "context" + "fmt" + "time" + + "github.com/daytonaio/daytona/cmd/daytona/config" + "github.com/daytonaio/daytona/internal/util" + apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" + "github.com/daytonaio/daytona/pkg/apiclient" + cmd_common "github.com/daytonaio/daytona/pkg/cmd/common" + "github.com/daytonaio/daytona/pkg/cmd/format" + "github.com/daytonaio/daytona/pkg/cmd/targetconfig" + "github.com/daytonaio/daytona/pkg/common" + "github.com/daytonaio/daytona/pkg/logs" + "github.com/daytonaio/daytona/pkg/views" + logs_view "github.com/daytonaio/daytona/pkg/views/logs" + target_view "github.com/daytonaio/daytona/pkg/views/target" + targetconfig_view "github.com/daytonaio/daytona/pkg/views/targetconfig" + "github.com/docker/docker/pkg/stringid" + "github.com/spf13/cobra" +) + +var targetCreateCmd = &cobra.Command{ + Use: "create", + Short: "Create a target", + Args: cobra.NoArgs, + Aliases: cmd_common.GetAliases("create"), + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.Background() + + apiClient, err := apiclient_util.GetApiClient(nil) + if err != nil { + return err + } + + c, err := config.GetConfig() + if err != nil { + return err + } + + activeProfile, err := c.GetActiveProfile() + if err != nil { + return err + } + + createTargetDto, err := CreateTargetDtoFlow(ctx, TargetCreationParams{ + ApiClient: apiClient, + ActiveProfileName: activeProfile.Name, + }) + if err != nil { + if common.IsCtrlCAbort(err) { + return nil + } else { + return err + } + } + + logsContext, stopLogs := context.WithCancel(context.Background()) + defer stopLogs() + + logs_view.SetupLongestPrefixLength([]string{createTargetDto.Name}) + + logs_view.DisplayLogEntry(logs.LogEntry{ + Label: createTargetDto.Name, + Msg: views.GetPrettyLogLine("Request submitted"), + }, logs_view.STATIC_INDEX) + + go cmd_common.ReadTargetLogs(logsContext, cmd_common.ReadLogParams{ + Id: createTargetDto.Id, + Label: &createTargetDto.Name, + ServerUrl: activeProfile.Api.Url, + ApiKey: activeProfile.Api.Key, + Follow: util.Pointer(true), + SkipPrefixLengthSetup: true, + }) + + _, res, err := apiClient.TargetAPI.CreateTarget(ctx).Target(*createTargetDto).Execute() + if err != nil { + return apiclient_util.HandleErrorResponse(res, err) + } + + err = cmd_common.AwaitTargetState(createTargetDto.Id, apiclient.ResourceStateNameStarted) + if err != nil { + return err + } + + // Ensure reading remaining logs is complete + time.Sleep(100 * time.Millisecond) + + views.RenderInfoMessage(fmt.Sprintf("Target '%s' set successfully and will be used by default", createTargetDto.Name)) + return nil + }, +} + +type TargetCreationParams struct { + ApiClient *apiclient.APIClient + ActiveProfileName string +} + +func CreateTargetDtoFlow(ctx context.Context, params TargetCreationParams) (*apiclient.CreateTargetDTO, error) { + var targetConfigView *targetconfig_view.TargetConfigView + + targetConfigList, res, err := params.ApiClient.TargetConfigAPI.ListTargetConfigs(ctx).Execute() + if err != nil { + return nil, apiclient_util.HandleErrorResponse(res, err) + } + + if len(targetConfigList) == 0 { + targetConfigView, err = targetconfig.TargetConfigCreationFlow(ctx, params.ApiClient, params.ActiveProfileName) + if err != nil { + return nil, err + } + + if targetConfigView == nil { + return nil, common.ErrCtrlCAbort + } + } else { + targetConfigView, err = targetconfig_view.GetTargetConfigFromPrompt(targetConfigList, params.ActiveProfileName, nil, true, "Use") + if err != nil { + return nil, err + } + + if targetConfigView == nil { + return nil, common.ErrCtrlCAbort + } + + if targetConfigView.Name == targetconfig_view.NewTargetConfigName { + targetConfigView, err = targetconfig.TargetConfigCreationFlow(ctx, params.ApiClient, params.ActiveProfileName) + if err != nil { + return nil, err + } + + if targetConfigView == nil { + return nil, common.ErrCtrlCAbort + } + } + } + + if format.FormatFlag != "" { + format.UnblockStdOut() + } + + targetList, res, err := params.ApiClient.TargetAPI.ListTargets(ctx).Execute() + if err != nil { + return nil, apiclient_util.HandleErrorResponse(res, err) + } + + var targetName string + if targetConfigView != nil { + targetName = targetConfigView.Name + } + + target_view.SetTargetNameView(&targetName, util.ArrayMap(targetList, func(t apiclient.TargetDTO) string { + return t.Name + })) + + id := stringid.GenerateRandomID() + id = stringid.TruncateID(id) + + return &apiclient.CreateTargetDTO{ + Id: id, + Name: targetName, + TargetConfigId: targetConfigView.Id, + }, nil +} diff --git a/pkg/cmd/target/delete.go b/pkg/cmd/target/delete.go new file mode 100644 index 0000000000..5fc0a938b3 --- /dev/null +++ b/pkg/cmd/target/delete.go @@ -0,0 +1,248 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package target + +import ( + "context" + "fmt" + "strings" + + "github.com/charmbracelet/huh" + "github.com/daytonaio/daytona/cmd/daytona/config" + apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" + "github.com/daytonaio/daytona/pkg/apiclient" + "github.com/daytonaio/daytona/pkg/cmd/common" + "github.com/daytonaio/daytona/pkg/views" + "github.com/daytonaio/daytona/pkg/views/target/selection" + views_util "github.com/daytonaio/daytona/pkg/views/util" + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" +) + +var yesFlag bool +var forceFlag bool + +var deleteCmd = &cobra.Command{ + Use: "delete [TARGET]...", + Short: "Delete a target", + Aliases: common.GetAliases("delete"), + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.Background() + + var targetDeleteList = []*apiclient.TargetDTO{} + var targetDeleteListNames = []string{} + apiClient, err := apiclient_util.GetApiClient(nil) + if err != nil { + return err + } + c, err := config.GetConfig() + if err != nil { + return err + } + + activeProfile, err := c.GetActiveProfile() + if err != nil { + return err + } + + if allFlag { + return deleteAllTargetsView(ctx, activeProfile.Id, apiClient) + } + + if len(args) == 0 { + targetList, res, err := apiClient.TargetAPI.ListTargets(ctx).Execute() + if err != nil { + return apiclient_util.HandleErrorResponse(res, err) + } + + if len(targetList) == 0 { + views_util.NotifyEmptyTargetList(false) + return nil + } + + targetDeleteList = selection.GetTargetsFromPrompt(targetList, "Delete") + for _, target := range targetDeleteList { + targetDeleteListNames = append(targetDeleteListNames, target.Name) + } + } else { + for _, arg := range args { + target, _, err := apiclient_util.GetTarget(arg) + if err != nil { + log.Error(fmt.Sprintf("[ %s ] : %v", arg, err)) + continue + } + targetDeleteList = append(targetDeleteList, target) + targetDeleteListNames = append(targetDeleteListNames, target.Name) + } + } + + if len(targetDeleteList) == 0 { + return nil + } + + var deleteTargetsFlag bool + + if !yesFlag { + form := huh.NewForm( + huh.NewGroup( + huh.NewConfirm(). + Title(fmt.Sprintf("Delete target(s): [%s]?", strings.Join(targetDeleteListNames, ", "))). + Description(fmt.Sprintf("Are you sure you want to delete the target(s): [%s]?", strings.Join(targetDeleteListNames, ", "))). + Value(&deleteTargetsFlag), + ), + ).WithTheme(views.GetCustomTheme()) + + err := form.Run() + if err != nil { + return err + } + } + + if !yesFlag && !deleteTargetsFlag { + fmt.Println("Operation canceled.") + } else { + for _, target := range targetDeleteList { + err := deleteTarget(ctx, activeProfile.Id, apiClient, target) + if err != nil { + log.Error(fmt.Sprintf("[ %s ] : %v", target.Name, err)) + } else { + views.RenderInfoMessage(fmt.Sprintf("Target '%s' successfully deleted", target.Name)) + } + } + } + return nil + }, + ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return getAllTargetsByState(nil) + }, +} + +func init() { + deleteCmd.Flags().BoolVarP(&allFlag, "all", "a", false, "Delete all targets") + deleteCmd.Flags().BoolVarP(&yesFlag, "yes", "y", false, "Confirm deletion without prompt") + deleteCmd.Flags().BoolVarP(&forceFlag, "force", "f", false, "Delete a target by force") +} + +func deleteAllTargetsView(ctx context.Context, activeProfileId string, apiClient *apiclient.APIClient) error { + var deleteAllTargetsFlag bool + + if yesFlag { + fmt.Println("Deleting all targets.") + err := deleteAllTargets(ctx, activeProfileId, apiClient) + if err != nil { + return err + } + } else { + form := huh.NewForm( + huh.NewGroup( + huh.NewConfirm(). + Title("Delete all targets?"). + Description("Are you sure you want to delete all targets?"). + Value(&deleteAllTargetsFlag), + ), + ).WithTheme(views.GetCustomTheme()) + + err := form.Run() + if err != nil { + return err + } + + if deleteAllTargetsFlag { + err := deleteAllTargets(ctx, activeProfileId, apiClient) + if err != nil { + return err + } + } else { + fmt.Println("Operation canceled.") + } + } + + return nil +} + +func deleteAllTargets(ctx context.Context, activeProfileId string, apiClient *apiclient.APIClient) error { + targetList, res, err := apiClient.TargetAPI.ListTargets(ctx).Execute() + if err != nil { + return apiclient_util.HandleErrorResponse(res, err) + } + + for _, target := range targetList { + err := deleteTarget(ctx, activeProfileId, apiClient, &target) + if err != nil { + log.Errorf("Failed to delete target %s: %v", target.Name, err) + continue + } + views.RenderInfoMessage(fmt.Sprintf("- Target '%s' successfully deleted", target.Name)) + } + return nil +} + +func deleteTarget(ctx context.Context, activeProfileId string, apiClient *apiclient.APIClient, target *apiclient.TargetDTO) error { + if len(target.Workspaces) > 0 { + err := deleteWorkspacesForTarget(ctx, apiClient, target) + if err != nil { + return err + } + } + + message := fmt.Sprintf("Deleting target %s", target.Name) + err := views_util.WithInlineSpinner(message, func() error { + res, err := apiClient.TargetAPI.DeleteTarget(ctx, target.Id).Force(forceFlag).Execute() + if err != nil { + return apiclient_util.HandleErrorResponse(res, err) + } + + err = config.RemoveSshEntries(activeProfileId, target.Id) + if err != nil { + return err + } + + err = common.AwaitTargetDeleted(target.Id) + if err != nil { + return err + } + + return nil + }) + + return err +} + +func deleteWorkspacesForTarget(ctx context.Context, apiClient *apiclient.APIClient, target *apiclient.TargetDTO) error { + var deleteWorkspacesFlag bool + + var targetWorkspacesNames []string + for _, workspace := range target.Workspaces { + targetWorkspacesNames = append(targetWorkspacesNames, workspace.Name) + } + + if !yesFlag { + form := huh.NewForm( + huh.NewGroup( + huh.NewConfirm(). + Title(fmt.Sprintf("Target '%s' is used by %d workspace(s). Delete workspaces: [%s]?", target.Name, len(target.Workspaces), strings.Join(targetWorkspacesNames, ", "))). + Description(fmt.Sprintf("Do you want to delete workspace(s): [%s]?", strings.Join(targetWorkspacesNames, ", "))). + Value(&deleteWorkspacesFlag), + ), + ).WithTheme(views.GetCustomTheme()) + + err := form.Run() + if err != nil { + return err + } + } + + if yesFlag || deleteWorkspacesFlag { + for _, workspace := range target.Workspaces { + err := common.DeleteWorkspace(ctx, apiClient, workspace.Id, workspace.Name, forceFlag) + if err != nil { + log.Errorf("Failed to delete workspace %s: %v", workspace.Name, err) + continue + } + views.RenderInfoMessage(fmt.Sprintf("Workspace '%s' successfully deleted", workspace.Name)) + } + } + + return nil +} diff --git a/pkg/cmd/target/info.go b/pkg/cmd/target/info.go new file mode 100644 index 0000000000..e6d09f30b3 --- /dev/null +++ b/pkg/cmd/target/info.go @@ -0,0 +1,84 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package target + +import ( + "context" + + apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" + "github.com/daytonaio/daytona/pkg/apiclient" + "github.com/daytonaio/daytona/pkg/cmd/common" + "github.com/daytonaio/daytona/pkg/cmd/format" + "github.com/daytonaio/daytona/pkg/views/target/info" + "github.com/daytonaio/daytona/pkg/views/target/selection" + views_util "github.com/daytonaio/daytona/pkg/views/util" + "github.com/spf13/cobra" +) + +var infoCmd = &cobra.Command{ + Use: "info [TARGET]", + Short: "Show target info", + Args: cobra.RangeArgs(0, 1), + Aliases: common.GetAliases("info"), + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.Background() + + apiClient, err := apiclient_util.GetApiClient(nil) + if err != nil { + return err + } + + var target *apiclient.TargetDTO + + if len(args) == 0 { + targetList, res, err := apiClient.TargetAPI.ListTargets(ctx).ShowOptions(showOptions).Execute() + if err != nil { + return apiclient_util.HandleErrorResponse(res, err) + } + + if len(targetList) == 0 { + views_util.NotifyEmptyTargetList(true) + return nil + } + + if format.FormatFlag != "" { + format.UnblockStdOut() + } + + target = selection.GetTargetFromPrompt(targetList, false, "View") + if format.FormatFlag != "" { + format.BlockStdOut() + } + + } else { + target, _, err = apiclient_util.GetTarget(args[0]) + if err != nil { + return err + } + } + + if target == nil { + return nil + } + + if format.FormatFlag != "" { + formattedData := format.NewFormatter(target) + formattedData.Print() + return nil + } + + info.Render(target, false) + return nil + }, + ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return getAllTargetsByState(nil) + }, +} + +var showOptions bool + +func init() { + infoCmd.Flags().BoolVarP(&showOptions, "show-options", "v", false, "Show target options") + format.RegisterFormatFlag(infoCmd) +} diff --git a/pkg/cmd/target/list.go b/pkg/cmd/target/list.go index 00677a9c11..bb761bdfbb 100644 --- a/pkg/cmd/target/list.go +++ b/pkg/cmd/target/list.go @@ -6,28 +6,31 @@ package target import ( "context" - apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" + "github.com/daytonaio/daytona/cmd/daytona/config" + "github.com/daytonaio/daytona/internal/util/apiclient" + "github.com/daytonaio/daytona/pkg/cmd/common" "github.com/daytonaio/daytona/pkg/cmd/format" list_view "github.com/daytonaio/daytona/pkg/views/target/list" "github.com/spf13/cobra" ) -var targetListCmd = &cobra.Command{ +var listCmd = &cobra.Command{ Use: "list", Short: "List targets", - Args: cobra.NoArgs, - Aliases: []string{"ls"}, + Args: cobra.ExactArgs(0), + Aliases: common.GetAliases("list"), RunE: func(cmd *cobra.Command, args []string) error { ctx := context.Background() - apiClient, err := apiclient_util.GetApiClient(nil) + apiClient, err := apiclient.GetApiClient(nil) if err != nil { return err } - targetList, res, err := apiClient.TargetAPI.ListTargets(ctx).Execute() + targetList, res, err := apiClient.TargetAPI.ListTargets(ctx).ShowOptions(showOptions).Execute() + if err != nil { - return apiclient_util.HandleErrorResponse(res, err) + return apiclient.HandleErrorResponse(res, err) } if format.FormatFlag != "" { @@ -36,11 +39,22 @@ var targetListCmd = &cobra.Command{ return nil } - list_view.ListTargets(targetList) + c, err := config.GetConfig() + if err != nil { + return err + } + + activeProfile, err := c.GetActiveProfile() + if err != nil { + return err + } + + list_view.ListTargets(targetList, activeProfile.Name, showOptions) return nil }, } func init() { - format.RegisterFormatFlag(targetListCmd) + listCmd.Flags().BoolVarP(&showOptions, "show-options", "v", false, "Show target options") + format.RegisterFormatFlag(listCmd) } diff --git a/pkg/cmd/target/logs.go b/pkg/cmd/target/logs.go new file mode 100644 index 0000000000..fcb1dec3bf --- /dev/null +++ b/pkg/cmd/target/logs.go @@ -0,0 +1,81 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package target + +import ( + "context" + + "github.com/daytonaio/daytona/cmd/daytona/config" + apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" + "github.com/daytonaio/daytona/pkg/apiclient" + "github.com/daytonaio/daytona/pkg/cmd/common" + cmd_common "github.com/daytonaio/daytona/pkg/cmd/common" + "github.com/daytonaio/daytona/pkg/views/target/selection" + views_util "github.com/daytonaio/daytona/pkg/views/util" + "github.com/spf13/cobra" +) + +var logsCmd = &cobra.Command{ + Use: "logs [TARGET]", + Short: "View the logs of a target", + Args: cobra.RangeArgs(0, 1), + Aliases: common.GetAliases("logs"), + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.Background() + c, err := config.GetConfig() + if err != nil { + return err + } + + activeProfile, err := c.GetActiveProfile() + if err != nil { + return err + } + + var target *apiclient.TargetDTO + apiClient, err := apiclient_util.GetApiClient(&activeProfile) + if err != nil { + return err + } + + if len(args) == 0 { + targetList, res, err := apiClient.TargetAPI.ListTargets(ctx).Execute() + if err != nil { + return apiclient_util.HandleErrorResponse(res, err) + } + if len(targetList) == 0 { + views_util.NotifyEmptyTargetList(true) + return nil + } + target = selection.GetTargetFromPrompt(targetList, false, "Get Logs For") + if target == nil { + return nil + } + } else { + target, _, err = apiclient_util.GetTarget(args[0]) + if err != nil { + return err + } + } + + cmd_common.ReadTargetLogs(ctx, cmd_common.ReadLogParams{ + Id: target.Id, + Label: &target.Name, + ServerUrl: activeProfile.Api.Url, + ApiKey: activeProfile.Api.Key, + Follow: &followFlag, + }) + + return nil + }, + ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return getAllTargetsByState(nil) + }, +} + +var followFlag bool + +func init() { + logsCmd.Flags().BoolVarP(&followFlag, "follow", "f", false, "Follow logs") +} diff --git a/pkg/cmd/target/remove.go b/pkg/cmd/target/remove.go deleted file mode 100644 index 82bd5cc8fc..0000000000 --- a/pkg/cmd/target/remove.go +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package target - -import ( - "context" - "fmt" - - "github.com/charmbracelet/huh" - "github.com/daytonaio/daytona/cmd/daytona/config" - apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" - "github.com/daytonaio/daytona/pkg/apiclient" - workspace_cmd "github.com/daytonaio/daytona/pkg/cmd/workspace" - "github.com/daytonaio/daytona/pkg/common" - "github.com/daytonaio/daytona/pkg/views" - "github.com/daytonaio/daytona/pkg/views/target" - views_util "github.com/daytonaio/daytona/pkg/views/util" - log "github.com/sirupsen/logrus" - "github.com/spf13/cobra" -) - -var yesFlag bool - -var targetRemoveCmd = &cobra.Command{ - Use: "remove [TARGET_NAME]", - Short: "Remove target", - Args: cobra.RangeArgs(0, 1), - Aliases: []string{"rm", "delete"}, - RunE: func(cmd *cobra.Command, args []string) error { - var selectedTargetName string - - ctx := context.Background() - apiClient, err := apiclient_util.GetApiClient(nil) - if err != nil { - return err - } - - c, err := config.GetConfig() - if err != nil { - return err - } - - if len(args) == 0 { - activeProfile, err := c.GetActiveProfile() - if err != nil { - return err - } - - targetList, res, err := apiClient.TargetAPI.ListTargets(ctx).Execute() - if err != nil { - return apiclient_util.HandleErrorResponse(res, err) - } - - if len(targetList) == 0 { - views_util.NotifyEmptyTargetList(false) - return nil - } - - selectedTarget, err := target.GetTargetFromPrompt(targetList, activeProfile.Name, nil, false, "Remove") - if err != nil { - if common.IsCtrlCAbort(err) { - return nil - } else { - return err - } - } - - selectedTargetName = selectedTarget.Name - } else { - selectedTargetName = args[0] - } - - if yesFlag { - fmt.Println("Deleting all workspaces.") - err := RemoveTargetWorkspaces(ctx, apiClient, selectedTargetName) - - if err != nil { - return err - } - } else { - var targetWorkspaceCount int - - workspaceList, res, err := apiClient.WorkspaceAPI.ListWorkspaces(ctx).Execute() - if err != nil { - return apiclient_util.HandleErrorResponse(res, err) - } - - for _, workspace := range workspaceList { - if workspace.Target == selectedTargetName { - targetWorkspaceCount++ - } - } - - if targetWorkspaceCount > 0 { - title := fmt.Sprintf("Delete %d workspaces within %s?", targetWorkspaceCount, selectedTargetName) - description := "You might not be able to easily remove these workspaces later." - - if targetWorkspaceCount == 1 { - title = fmt.Sprintf("Delete %d workspace within %s?", targetWorkspaceCount, selectedTargetName) - description = "You might not be able to easily remove this workspace later." - } - - form := huh.NewForm( - huh.NewGroup( - huh.NewConfirm(). - Title(title). - Description(description). - Value(&yesFlag), - ), - ).WithTheme(views.GetCustomTheme()) - - err := form.Run() - if err != nil { - return err - } - - if yesFlag { - err := RemoveTargetWorkspaces(ctx, apiClient, selectedTargetName) - if err != nil { - return err - } - } else { - fmt.Println("Proceeding with target removal without deleting workspaces.") - } - } - } - - res, err := apiClient.TargetAPI.RemoveTarget(ctx, selectedTargetName).Execute() - if err != nil { - return apiclient_util.HandleErrorResponse(res, err) - } - - views.RenderInfoMessageBold(fmt.Sprintf("Target %s removed successfully", selectedTargetName)) - return nil - }, -} - -func init() { - targetRemoveCmd.Flags().BoolVarP(&yesFlag, "yes", "y", false, "Confirm deletion of all workspaces without prompt") -} - -func RemoveTargetWorkspaces(ctx context.Context, client *apiclient.APIClient, target string) error { - workspaceList, res, err := client.WorkspaceAPI.ListWorkspaces(ctx).Execute() - if err != nil { - return apiclient_util.HandleErrorResponse(res, err) - } - - for _, workspace := range workspaceList { - if workspace.Target != target { - continue - } - err := workspace_cmd.RemoveWorkspace(ctx, client, &workspace, false) - if err != nil { - log.Errorf("Failed to delete workspace %s: %v", workspace.Name, err) - continue - } - - views.RenderInfoMessage(fmt.Sprintf("- Workspace '%s' successfully deleted", workspace.Name)) - } - - return nil -} diff --git a/pkg/cmd/target/restart.go b/pkg/cmd/target/restart.go new file mode 100644 index 0000000000..0699eec128 --- /dev/null +++ b/pkg/cmd/target/restart.go @@ -0,0 +1,64 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package target + +import ( + "context" + "fmt" + + "github.com/daytonaio/daytona/internal/util" + apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" + "github.com/daytonaio/daytona/pkg/apiclient" + "github.com/daytonaio/daytona/pkg/views" + "github.com/daytonaio/daytona/pkg/views/target/selection" + views_util "github.com/daytonaio/daytona/pkg/views/util" + "github.com/spf13/cobra" +) + +var restartCmd = &cobra.Command{ + Use: "restart [TARGET]", + Short: "Restart a target", + Args: cobra.RangeArgs(0, 1), + RunE: func(cmd *cobra.Command, args []string) error { + var target *apiclient.TargetDTO + ctx := context.Background() + + apiClient, err := apiclient_util.GetApiClient(nil) + if err != nil { + return err + } + + if len(args) == 0 { + targetList, res, err := apiClient.TargetAPI.ListTargets(ctx).Execute() + if err != nil { + return apiclient_util.HandleErrorResponse(res, err) + } + + if len(targetList) == 0 { + views_util.NotifyEmptyTargetList(true) + return nil + } + + target = selection.GetTargetFromPrompt(targetList, false, "Restart") + if target == nil { + return nil + } + } else { + target, _, err = apiclient_util.GetTarget(args[0]) + if err != nil { + return err + } + } + + err = StartTarget(apiClient, *target, true) + if err != nil { + return err + } + views.RenderInfoMessage(fmt.Sprintf("Target '%s' successfully restarted", target.Name)) + return nil + }, + ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return getAllTargetsByState(util.Pointer(apiclient.ResourceStateNameStarted)) + }, +} diff --git a/pkg/cmd/target/set.go b/pkg/cmd/target/set.go deleted file mode 100644 index 7ba4de9356..0000000000 --- a/pkg/cmd/target/set.go +++ /dev/null @@ -1,337 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package target - -import ( - "context" - "encoding/json" - "errors" - "fmt" - "io" - "os" - "regexp" - "sort" - - "github.com/daytonaio/daytona/cmd/daytona/config" - internal_util "github.com/daytonaio/daytona/internal/util" - apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" - "github.com/daytonaio/daytona/pkg/apiclient" - "github.com/daytonaio/daytona/pkg/cmd/provider" - "github.com/daytonaio/daytona/pkg/common" - "github.com/daytonaio/daytona/pkg/provider/manager" - "github.com/daytonaio/daytona/pkg/views" - provider_view "github.com/daytonaio/daytona/pkg/views/provider" - "github.com/daytonaio/daytona/pkg/views/target" - target_view "github.com/daytonaio/daytona/pkg/views/target" - "github.com/spf13/cobra" - - log "github.com/sirupsen/logrus" -) - -var pipeFile string - -var TargetSetCmd = &cobra.Command{ - Use: "set", - Short: "Set provider target", - Args: cobra.NoArgs, - Aliases: []string{"s", "add", "update", "register", "edit"}, - RunE: func(cmd *cobra.Command, args []string) error { - ctx := context.Background() - var isNewProvider bool - var input []byte - var err error - - if pipeFile == "-" { - input, err = io.ReadAll(os.Stdin) - if err != nil { - return fmt.Errorf("failed to read from stdin: %w", err) - } - return handleTargetJSON(input) - } else if pipeFile != "" { - input, err = os.ReadFile(pipeFile) - if err != nil { - return fmt.Errorf("failed to read file %s: %w", pipeFile, err) - } - return handleTargetJSON(input) - } - - apiClient, err := apiclient_util.GetApiClient(nil) - if err != nil { - return err - } - - c, err := config.GetConfig() - if err != nil { - return err - } - - activeProfile, err := c.GetActiveProfile() - if err != nil { - return err - } - - serverConfig, res, err := apiClient.ServerAPI.GetConfigExecute(apiclient.ApiGetConfigRequest{}) - if err != nil { - return apiclient_util.HandleErrorResponse(res, err) - } - - providersManifest, err := manager.NewProviderManager(manager.ProviderManagerConfig{ - RegistryUrl: serverConfig.RegistryUrl, - }).GetProvidersManifest() - if err != nil { - log.Error(err) - } - - var latestProviders []apiclient.Provider - if providersManifest != nil { - providersManifestLatest := providersManifest.GetLatestVersions() - if providersManifestLatest == nil { - return errors.New("could not get latest provider versions") - } - - latestProviders = provider.GetProviderListFromManifest(providersManifestLatest) - } else { - fmt.Println("Could not get provider manifest. Can't check for new providers to install") - } - - providerViewList, err := provider.GetProviderViewOptions(apiClient, latestProviders, ctx) - if err != nil { - return err - } - - selectedProvider, err := provider_view.GetProviderFromPrompt(providerViewList, "Choose a Provider", false) - if err != nil { - if common.IsCtrlCAbort(err) { - return nil - } else { - return err - } - } - - if selectedProvider == nil { - return nil - } - - if selectedProvider.Installed != nil && !*selectedProvider.Installed { - if providersManifest == nil { - return errors.New("could not get providers manifest") - } - err = provider.InstallProvider(apiClient, *selectedProvider, providersManifest) - if err != nil { - return err - } - isNewProvider = true - } - - targets, res, err := apiClient.TargetAPI.ListTargets(ctx).Execute() - if err != nil { - return apiclient_util.HandleErrorResponse(res, err) - } - - filteredTargets := []apiclient.ProviderTarget{} - for _, t := range targets { - if t.ProviderInfo.Name == selectedProvider.Name { - filteredTargets = append(filteredTargets, t) - } - } - - var selectedTarget *target_view.TargetView - - if !isNewProvider || len(filteredTargets) > 0 { - selectedTarget, err = target.GetTargetFromPrompt(filteredTargets, activeProfile.Name, nil, true, "Set") - if err != nil { - if common.IsCtrlCAbort(err) { - return nil - } else { - return err - } - } - } else { - selectedTarget = &target_view.TargetView{ - Name: target.NewTargetName, - Options: "{}", - } - } - - if selectedTarget.Name == target.NewTargetName { - selectedTarget.Name = "" - err = target.NewTargetNameInput(&selectedTarget.Name, internal_util.ArrayMap(targets, func(t apiclient.ProviderTarget) string { - return t.Name - })) - if err != nil { - return err - } - } - - targetManifest, res, err := apiClient.ProviderAPI.GetTargetManifest(context.Background(), selectedProvider.Name).Execute() - if err != nil { - return apiclient_util.HandleErrorResponse(res, err) - } - - err = target.SetTargetForm(selectedTarget, *targetManifest) - if err != nil { - return err - } - - targetData := apiclient.CreateProviderTargetDTO{ - Name: selectedTarget.Name, - Options: selectedTarget.Options, - ProviderInfo: apiclient.ProviderProviderInfo{ - Name: selectedProvider.Name, - Version: selectedProvider.Version, - }, - } - - res, err = apiClient.TargetAPI.SetTarget(context.Background()).Target(targetData).Execute() - if err != nil { - return apiclient_util.HandleErrorResponse(res, err) - } - - views.RenderInfoMessage("Target set successfully and will be used by default") - return nil - }, -} - -func handleTargetJSON(data []byte) error { - ctx := context.Background() - - apiClient, err := apiclient_util.GetApiClient(nil) - if err != nil { - return err - } - var selectedTarget *target_view.TargetView - err = parseJSON(data, &selectedTarget) - if err != nil { - return fmt.Errorf("failed to parse input: %w", err) - } - - if selectedTarget.Name == "" { - return errors.New("invalid input: 'name' field is required") - } - if selectedTarget.Options == "" { - return errors.New("option fields are required to setup your target") - } - targetManifest, res, err := apiClient.ProviderAPI.GetTargetManifest(ctx, selectedTarget.ProviderInfo.Name).Execute() - if err != nil { - return apiclient_util.HandleErrorResponse(res, err) - } - err = validateProperty(*targetManifest, selectedTarget) - if err != nil { - return err - } - targetData := apiclient.CreateProviderTargetDTO{ - Name: selectedTarget.Name, - Options: selectedTarget.Options, - ProviderInfo: apiclient.ProviderProviderInfo{ - Name: selectedTarget.ProviderInfo.Name, - Version: selectedTarget.ProviderInfo.Version, - }, - } - res, err = apiClient.TargetAPI.SetTarget(ctx).Target(targetData).Execute() - if err != nil { - return apiclient_util.HandleErrorResponse(res, err) - } - views.RenderInfoMessage("Target set successfully and will be used by default") - return nil -} - -func parseJSON(data []byte, v interface{}) error { - if err := json.Unmarshal(data, v); err == nil { - return nil - } - return errors.New("input is not a valid JSON") -} - -func validateProperty(targetManifest map[string]apiclient.ProviderProviderTargetProperty, target *target_view.TargetView) error { - optionMap := make(map[string]interface{}) - if err := json.Unmarshal([]byte(target.Options), &optionMap); err != nil { - return fmt.Errorf("failed to parse options JSON: %w", err) - } - for optionKey := range optionMap { - if _, exists := targetManifest[optionKey]; !exists { - return fmt.Errorf("invalid property '%s' for target manifest '%s'", optionKey, target.Name) - } - } - - sortedKeys := make([]string, 0, len(targetManifest)) - for k := range targetManifest { - sortedKeys = append(sortedKeys, k) - } - sort.Strings(sortedKeys) - - for _, name := range sortedKeys { - if _, present := optionMap[name]; !present { - continue - } - - property := targetManifest[name] - if property.DisabledPredicate != nil && *property.DisabledPredicate != "" { - if matched, err := regexp.Match(*property.DisabledPredicate, []byte(target.Name)); err == nil && matched { - if !contains(property.Options, optionMap[name]) { - return fmt.Errorf("unexpected property '%s' for target manifest '%s'", name, target.Name) - } - continue - } - } - - switch *property.Type { - case apiclient.ProviderTargetPropertyTypeFloat, apiclient.ProviderTargetPropertyTypeInt: - _, isNumber := optionMap[name].(float64) - if !isNumber { - return fmt.Errorf("invalid type for %s, expected number", name) - } - - case apiclient.ProviderTargetPropertyTypeString: - _, isString := optionMap[name].(string) - if !isString { - return fmt.Errorf("invalid type for %s, expected string", name) - } - - case apiclient.ProviderTargetPropertyTypeBoolean: - _, isBool := optionMap[name].(bool) - if !isBool { - return fmt.Errorf("invalid type for %s, expected boolean", name) - } - - case apiclient.ProviderTargetPropertyTypeOption: - optionValue, ok := optionMap[name].(string) - if !ok { - return fmt.Errorf("invalid value for '%s': expected a string", name) - } - valid := false - for _, allowedOption := range property.Options { - if optionValue == allowedOption { - valid = true - break - } - } - if !valid { - return fmt.Errorf("unexpected property '%s' for target manifest '%s' : valid properties are %v", optionValue, target.Name, property.Options) - } - - case apiclient.ProviderTargetPropertyTypeFilePath: - _, isString := optionMap[name].(string) - if !isString { - return fmt.Errorf("invalid type for %s, expected file path string", name) - } - - default: - return fmt.Errorf("unsupported provider type: %s", *property.Type) - } - } - return nil -} - -func contains(slice []string, item interface{}) bool { - for _, val := range slice { - if val == item { - return true - } - } - return false -} - -func init() { - TargetSetCmd.Flags().StringVarP(&pipeFile, "file", "f", "", "Path to JSON file for target configuration, use '-' to read from stdin") -} diff --git a/pkg/cmd/target/setdefault.go b/pkg/cmd/target/setdefault.go index 0388c6122f..a29b3fcc39 100644 --- a/pkg/cmd/target/setdefault.go +++ b/pkg/cmd/target/setdefault.go @@ -7,21 +7,21 @@ import ( "context" "fmt" - "github.com/daytonaio/daytona/cmd/daytona/config" apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" - "github.com/daytonaio/daytona/pkg/common" + "github.com/daytonaio/daytona/pkg/apiclient" + "github.com/daytonaio/daytona/pkg/cmd/common" "github.com/daytonaio/daytona/pkg/views" - target_view "github.com/daytonaio/daytona/pkg/views/target" + "github.com/daytonaio/daytona/pkg/views/target/selection" views_util "github.com/daytonaio/daytona/pkg/views/util" "github.com/spf13/cobra" ) -var targetSetDefaultCmd = &cobra.Command{ - Use: "set-default [TARGET_NAME]", - Short: "Set target to be used by default", - Args: cobra.RangeArgs(0, 1), +var setDefaultCmd = &cobra.Command{ + Use: "set-default [TARGET]", + Short: "Set default target", + Args: cobra.RangeArgs(0, 1), + Aliases: common.GetAliases("set-default"), RunE: func(cmd *cobra.Command, args []string) error { - var targetName string ctx := context.Background() apiClient, err := apiclient_util.GetApiClient(nil) @@ -29,6 +29,8 @@ var targetSetDefaultCmd = &cobra.Command{ return err } + var target *apiclient.TargetDTO + if len(args) == 0 { targetList, res, err := apiClient.TargetAPI.ListTargets(ctx).Execute() if err != nil { @@ -40,40 +42,27 @@ var targetSetDefaultCmd = &cobra.Command{ return nil } - c, err := config.GetConfig() - if err != nil { - return err - } - - activeProfile, err := c.GetActiveProfile() + target = selection.GetTargetFromPrompt(targetList, false, "Set As Default") + } else { + target, _, err = apiclient_util.GetTarget(args[0]) if err != nil { return err } + } - selectedTarget, err := target_view.GetTargetFromPrompt(targetList, activeProfile.Name, nil, false, "Make Default") - if err != nil { - if common.IsCtrlCAbort(err) { - return nil - } else { - return err - } - } - - if selectedTarget == nil { - return nil - } - - targetName = selectedTarget.Name - } else { - targetName = args[0] + if target == nil { + return nil } - res, err := apiClient.TargetAPI.SetDefaultTarget(ctx, targetName).Execute() + res, err := apiClient.TargetAPI.SetDefaultTarget(ctx, target.Id).Execute() if err != nil { return apiclient_util.HandleErrorResponse(res, err) } - views.RenderInfoMessage(fmt.Sprintf("Target '%s' set as default", targetName)) + views.RenderInfoMessage(fmt.Sprintf("Target '%s' set as default", target.Name)) return nil }, + ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return getAllTargetsByState(nil) + }, } diff --git a/pkg/cmd/target/ssh.go b/pkg/cmd/target/ssh.go new file mode 100644 index 0000000000..6be72468ce --- /dev/null +++ b/pkg/cmd/target/ssh.go @@ -0,0 +1,116 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package target + +import ( + "context" + + "github.com/daytonaio/daytona/cmd/daytona/config" + apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" + "github.com/daytonaio/daytona/pkg/apiclient" + "github.com/daytonaio/daytona/pkg/cmd/common" + "github.com/daytonaio/daytona/pkg/ide" + ide_views "github.com/daytonaio/daytona/pkg/views/ide" + "github.com/daytonaio/daytona/pkg/views/target/selection" + views_util "github.com/daytonaio/daytona/pkg/views/util" + "github.com/spf13/cobra" +) + +var sshOptions []string + +var sshCmd = &cobra.Command{ + Use: "ssh [TARGET] [CMD...]", + Short: "SSH into a target using the terminal", + Args: cobra.ArbitraryArgs, + RunE: func(cmd *cobra.Command, args []string) error { + c, err := config.GetConfig() + if err != nil { + return err + } + + activeProfile, err := c.GetActiveProfile() + if err != nil { + return err + } + + ctx := context.Background() + var tg *apiclient.TargetDTO + + apiClient, err := apiclient_util.GetApiClient(&activeProfile) + if err != nil { + return err + } + + if len(args) == 0 { + targetList, res, err := apiClient.TargetAPI.ListTargets(ctx).Execute() + if err != nil { + return apiclient_util.HandleErrorResponse(res, err) + } + + if len(targetList) == 0 { + views_util.NotifyEmptyWorkspaceList(true) + return nil + } + + tg = selection.GetTargetFromPrompt(targetList, false, "SSH Into") + if tg == nil { + return nil + } + } else { + tg, _, err = apiclient_util.GetTarget(args[0]) + if err != nil { + return err + } + } + + if tg.TargetConfig.ProviderInfo.AgentlessTarget != nil && *tg.TargetConfig.ProviderInfo.AgentlessTarget { + return agentlessTargetError(tg.TargetConfig.ProviderInfo.Name) + } + + if tg.State.Name == apiclient.ResourceStateNameStopped { + tgRunningStatus, err := autoStartTarget(*tg) + if err != nil { + return err + } + if !tgRunningStatus { + return nil + } + } + + sshArgs := []string{} + if len(args) > 1 { + sshArgs = append(sshArgs, args[1:]...) + } + + return ide.OpenTerminalSsh(activeProfile, tg.Id, nil, sshOptions, sshArgs...) + }, + ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return common.GetWorkspaceNameCompletions() + }, +} + +func init() { + sshCmd.Flags().BoolVarP(&yesFlag, "yes", "y", false, "Automatically confirm any prompts") + sshCmd.Flags().StringArrayVarP(&sshOptions, "option", "o", []string{}, "Specify SSH options in KEY=VALUE format.") +} + +func autoStartTarget(target apiclient.TargetDTO) (bool, error) { + if !yesFlag { + if !ide_views.RunStartTargetForm(target.Name) { + return false, nil + } + } + + apiClient, err := apiclient_util.GetApiClient(nil) + if err != nil { + return false, err + } + + err = StartTarget(apiClient, target, false) + if err != nil { + return false, err + } + + return true, nil +} diff --git a/pkg/cmd/target/start.go b/pkg/cmd/target/start.go new file mode 100644 index 0000000000..bbe28fcc6e --- /dev/null +++ b/pkg/cmd/target/start.go @@ -0,0 +1,216 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package target + +import ( + "context" + "fmt" + "net/http" + "time" + + "github.com/daytonaio/daytona/cmd/daytona/config" + "github.com/daytonaio/daytona/internal/util" + apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" + "github.com/daytonaio/daytona/pkg/apiclient" + cmd_common "github.com/daytonaio/daytona/pkg/cmd/common" + "github.com/daytonaio/daytona/pkg/views" + "github.com/daytonaio/daytona/pkg/views/target/selection" + views_util "github.com/daytonaio/daytona/pkg/views/util" + + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" +) + +var allFlag bool + +var startCmd = &cobra.Command{ + Use: "start [TARGET]", + Short: "Start a target", + Args: cobra.RangeArgs(0, 1), + RunE: func(cmd *cobra.Command, args []string) error { + var selectedTargetsNames []string + + ctx := context.Background() + + apiClient, err := apiclient_util.GetApiClient(nil) + if err != nil { + return err + } + + if allFlag { + return startAllTargets() + } + + if len(args) == 0 { + targetList, res, err := apiClient.TargetAPI.ListTargets(ctx).Execute() + if err != nil { + return apiclient_util.HandleErrorResponse(res, err) + } + + if len(targetList) == 0 { + views_util.NotifyEmptyTargetList(true) + return nil + } + selectedTargets := selection.GetTargetsFromPrompt(targetList, "Start") + for _, targets := range selectedTargets { + selectedTargetsNames = append(selectedTargetsNames, targets.Name) + } + } else { + selectedTargetsNames = append(selectedTargetsNames, args[0]) + } + + if len(selectedTargetsNames) == 1 { + targetName := selectedTargetsNames[0] + + target, _, err := apiclient_util.GetTarget(targetName) + if err != nil { + return err + } + + err = StartTarget(apiClient, *target, false) + if err != nil { + return err + } + + views.RenderInfoMessage(fmt.Sprintf("Target '%s' started successfully", targetName)) + } else { + for _, targetName := range selectedTargetsNames { + target, _, err := apiclient_util.GetTarget(targetName) + if err != nil { + return err + } + + err = StartTarget(apiClient, *target, false) + if err != nil { + log.Errorf("Failed to start target %s: %v\n\n", targetName, err) + continue + } + views.RenderInfoMessage(fmt.Sprintf("- Target '%s' started successfully", targetName)) + } + } + return nil + }, + ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return getAllTargetsByState(util.Pointer(apiclient.ResourceStateNameStopped)) + }, +} + +func init() { + startCmd.PersistentFlags().BoolVarP(&allFlag, "all", "a", false, "Start all targets") + startCmd.PersistentFlags().BoolVarP(&yesFlag, "yes", "y", false, "Automatically confirm any prompts") +} + +func StartTarget(apiClient *apiclient.APIClient, target apiclient.TargetDTO, restart bool) error { + ctx := context.Background() + timeFormat := time.Now().Format("2006-01-02 15:04:05") + from, err := time.Parse("2006-01-02 15:04:05", timeFormat) + if err != nil { + return err + } + + c, err := config.GetConfig() + if err != nil { + return err + } + + activeProfile, err := c.GetActiveProfile() + if err != nil { + return err + } + + if target.TargetConfig.ProviderInfo.AgentlessTarget != nil && *target.TargetConfig.ProviderInfo.AgentlessTarget { + return agentlessTargetError(target.TargetConfig.ProviderInfo.Name) + } + + logsContext, stopLogs := context.WithCancel(context.Background()) + go cmd_common.ReadTargetLogs(logsContext, cmd_common.ReadLogParams{ + Id: target.Id, + Label: &target.Name, + ServerUrl: activeProfile.Api.Url, + ApiKey: activeProfile.Api.Key, + Follow: util.Pointer(true), + From: &from, + }) + + var res *http.Response + + if restart { + res, err = apiClient.TargetAPI.RestartTarget(ctx, target.Id).Execute() + } else { + res, err = apiClient.TargetAPI.StartTarget(ctx, target.Id).Execute() + } + + if err != nil { + stopLogs() + return apiclient_util.HandleErrorResponse(res, err) + } + + err = cmd_common.AwaitTargetState(target.Id, apiclient.ResourceStateNameStarted) + + // Ensure reading remaining logs is completed + time.Sleep(100 * time.Millisecond) + + stopLogs() + return err +} + +func startAllTargets() error { + ctx := context.Background() + apiClient, err := apiclient_util.GetApiClient(nil) + if err != nil { + return err + } + + targetList, res, err := apiClient.TargetAPI.ListTargets(ctx).Execute() + if err != nil { + return apiclient_util.HandleErrorResponse(res, err) + } + + for _, target := range targetList { + err := StartTarget(apiClient, target, false) + if err != nil { + log.Errorf("Failed to start target %s: %v\n\n", target.Name, err) + continue + } + + views.RenderInfoMessage(fmt.Sprintf("- Target '%s' started successfully", target.Name)) + } + return nil +} + +func getAllTargetsByState(state *apiclient.ModelsResourceStateName) ([]string, cobra.ShellCompDirective) { + ctx := context.Background() + apiClient, err := apiclient_util.GetApiClient(nil) + if err != nil { + return nil, cobra.ShellCompDirectiveNoFileComp + } + + targetList, _, err := apiClient.TargetAPI.ListTargets(ctx).Execute() + if err != nil { + return nil, cobra.ShellCompDirectiveNoFileComp + } + + var choices []string + for _, target := range targetList { + if state == nil { + choices = append(choices, target.Name) + break + } else { + if *state == apiclient.ResourceStateNameStarted { + choices = append(choices, target.Name) + break + } + if *state == apiclient.ResourceStateNameStopped { + choices = append(choices, target.Name) + break + } + } + } + + return choices, cobra.ShellCompDirectiveNoFileComp +} + +func agentlessTargetError(providerName string) error { + return fmt.Errorf("%s does not use a target-level agent; you may continue without managing its state or trying to access it", providerName) +} diff --git a/pkg/cmd/target/stop.go b/pkg/cmd/target/stop.go new file mode 100644 index 0000000000..8500b6750f --- /dev/null +++ b/pkg/cmd/target/stop.go @@ -0,0 +1,180 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package target + +import ( + "context" + "fmt" + "time" + + "github.com/daytonaio/daytona/cmd/daytona/config" + "github.com/daytonaio/daytona/internal/util" + apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" + "github.com/daytonaio/daytona/pkg/apiclient" + cmd_common "github.com/daytonaio/daytona/pkg/cmd/common" + "github.com/daytonaio/daytona/pkg/views" + logs_view "github.com/daytonaio/daytona/pkg/views/logs" + "github.com/daytonaio/daytona/pkg/views/target/selection" + views_util "github.com/daytonaio/daytona/pkg/views/util" + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" +) + +var stopCmd = &cobra.Command{ + Use: "stop [TARGET]", + Short: "Stop a target", + Args: cobra.RangeArgs(0, 1), + RunE: func(cmd *cobra.Command, args []string) error { + timeFormat := time.Now().Format("2006-01-02 15:04:05") + from, err := time.Parse("2006-01-02 15:04:05", timeFormat) + if err != nil { + return err + } + + c, err := config.GetConfig() + if err != nil { + return err + } + + activeProfile, err := c.GetActiveProfile() + if err != nil { + return err + } + + if allFlag { + return stopAllTargets(activeProfile, from) + } + + ctx := context.Background() + + apiClient, err := apiclient_util.GetApiClient(nil) + if err != nil { + return err + } + + if len(args) == 0 { + targetList, res, err := apiClient.TargetAPI.ListTargets(ctx).Execute() + if err != nil { + return apiclient_util.HandleErrorResponse(res, err) + } + + if len(targetList) == 0 { + views_util.NotifyEmptyTargetList(true) + return nil + } + + selectedTargets := selection.GetTargetsFromPrompt(targetList, "Stop") + + for _, target := range selectedTargets { + err := StopTarget(apiClient, *target) + if err != nil { + log.Errorf("Failed to stop target %s: %v\n\n", target.Name, err) + continue + } + + logs_view.SetupLongestPrefixLength(util.ArrayMap(targetList, func(t apiclient.TargetDTO) string { + return t.Name + })) + + cmd_common.ReadTargetLogs(ctx, cmd_common.ReadLogParams{ + Id: target.Id, + Label: &target.Name, + ServerUrl: activeProfile.Api.Url, + ApiKey: activeProfile.Api.Key, + From: &from, + SkipPrefixLengthSetup: true, + }) + views.RenderInfoMessage(fmt.Sprintf("- Target '%s' successfully stopped", target.Name)) + } + } else { + targetId := args[0] + + target, _, err := apiclient_util.GetTarget(targetId) + if err != nil { + return err + } + + err = StopTarget(apiClient, *target) + if err != nil { + return err + } + + cmd_common.ReadTargetLogs(ctx, cmd_common.ReadLogParams{ + Id: target.Id, + Label: &target.Name, + ServerUrl: activeProfile.Api.Url, + ApiKey: activeProfile.Api.Key, + From: &from, + }) + + views.RenderInfoMessage(fmt.Sprintf("Target '%s' successfully stopped", targetId)) + } + return nil + }, + ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return getAllTargetsByState(util.Pointer(apiclient.ResourceStateNameStarted)) + }, +} + +func init() { + stopCmd.Flags().BoolVarP(&allFlag, "all", "a", false, "Stop all targets") +} + +func stopAllTargets(activeProfile config.Profile, from time.Time) error { + ctx := context.Background() + apiClient, err := apiclient_util.GetApiClient(nil) + if err != nil { + return err + } + + targetList, res, err := apiClient.TargetAPI.ListTargets(ctx).Execute() + if err != nil { + return apiclient_util.HandleErrorResponse(res, err) + } + + for _, target := range targetList { + err := StopTarget(apiClient, target) + if err != nil { + log.Errorf("Failed to stop target %s: %v\n\n", target.Name, err) + continue + } + + logs_view.SetupLongestPrefixLength(util.ArrayMap(targetList, func(t apiclient.TargetDTO) string { + return t.Name + })) + + cmd_common.ReadTargetLogs(ctx, cmd_common.ReadLogParams{ + Id: target.Id, + Label: &target.Name, + ServerUrl: activeProfile.Api.Url, + ApiKey: activeProfile.Api.Key, + From: &from, + SkipPrefixLengthSetup: true, + }) + views.RenderInfoMessage(fmt.Sprintf("- Target '%s' successfully stopped", target.Name)) + } + return nil +} + +func StopTarget(apiClient *apiclient.APIClient, target apiclient.TargetDTO) error { + ctx := context.Background() + + if target.TargetConfig.ProviderInfo.AgentlessTarget != nil && *target.TargetConfig.ProviderInfo.AgentlessTarget { + return agentlessTargetError(target.TargetConfig.ProviderInfo.Name) + } + + err := views_util.WithInlineSpinner(fmt.Sprintf("Target '%s' is stopping", target.Name), func() error { + res, err := apiClient.TargetAPI.StopTarget(ctx, target.Id).Execute() + if err != nil { + return apiclient_util.HandleErrorResponse(res, err) + } + + return cmd_common.AwaitTargetState(target.Id, apiclient.ResourceStateNameStarted) + }) + if err != nil { + return err + } + + return nil +} diff --git a/pkg/cmd/target/target.go b/pkg/cmd/target/target.go index 2253c91081..d6d4beff79 100644 --- a/pkg/cmd/target/target.go +++ b/pkg/cmd/target/target.go @@ -10,13 +10,21 @@ import ( var TargetCmd = &cobra.Command{ Use: "target", - Short: "Manage provider targets", - GroupID: util.SERVER_GROUP, + Args: cobra.NoArgs, + Short: "Manage targets", + GroupID: util.TARGET_GROUP, + Aliases: []string{"targets", "tg"}, } func init() { - TargetCmd.AddCommand(targetListCmd) - TargetCmd.AddCommand(TargetSetCmd) - TargetCmd.AddCommand(targetRemoveCmd) - TargetCmd.AddCommand(targetSetDefaultCmd) + TargetCmd.AddCommand(targetCreateCmd) + TargetCmd.AddCommand(deleteCmd) + TargetCmd.AddCommand(infoCmd) + TargetCmd.AddCommand(restartCmd) + TargetCmd.AddCommand(startCmd) + TargetCmd.AddCommand(stopCmd) + TargetCmd.AddCommand(logsCmd) + TargetCmd.AddCommand(listCmd) + TargetCmd.AddCommand(setDefaultCmd) + TargetCmd.AddCommand(sshCmd) } diff --git a/pkg/cmd/targetconfig/create.go b/pkg/cmd/targetconfig/create.go new file mode 100644 index 0000000000..29491742ff --- /dev/null +++ b/pkg/cmd/targetconfig/create.go @@ -0,0 +1,420 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package targetconfig + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "io" + "os" + "regexp" + "sort" + + "github.com/daytonaio/daytona/cmd/daytona/config" + "github.com/daytonaio/daytona/internal/util" + apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" + "github.com/daytonaio/daytona/pkg/apiclient" + cmd_common "github.com/daytonaio/daytona/pkg/cmd/common" + "github.com/daytonaio/daytona/pkg/cmd/provider" + "github.com/daytonaio/daytona/pkg/common" + "github.com/daytonaio/daytona/pkg/views" + provider_view "github.com/daytonaio/daytona/pkg/views/provider" + "github.com/daytonaio/daytona/pkg/views/provider/install" + "github.com/daytonaio/daytona/pkg/views/targetconfig" + "github.com/spf13/cobra" +) + +var pipeFile string + +var TargetConfigCreateCmd = &cobra.Command{ + Use: "create", + Short: "Create target config", + Args: cobra.NoArgs, + Aliases: cmd_common.GetAliases("create"), + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.Background() + var input []byte + var err error + + if pipeFile == "-" { + input, err = io.ReadAll(os.Stdin) + if err != nil { + return fmt.Errorf("failed to read from stdin: %w", err) + } + return handleTargetConfigJSON(input) + } else if pipeFile != "" { + input, err = os.ReadFile(pipeFile) + if err != nil { + return fmt.Errorf("failed to read file %s: %w", pipeFile, err) + } + return handleTargetConfigJSON(input) + } + + apiClient, err := apiclient_util.GetApiClient(nil) + if err != nil { + return err + } + + c, err := config.GetConfig() + if err != nil { + return err + } + + activeProfile, err := c.GetActiveProfile() + if err != nil { + return err + } + + targetConfig, err := TargetConfigCreationFlow(ctx, apiClient, activeProfile.Name) + if err != nil { + return err + } + + if targetConfig == nil { + return nil + } + + views.RenderInfoMessage(fmt.Sprintf("Target config '%s' created successfully", targetConfig.Name)) + return nil + }, +} + +func TargetConfigCreationFlow(ctx context.Context, apiClient *apiclient.APIClient, activeProfileName string) (*targetconfig.TargetConfigView, error) { + installedProviderList, _, err := apiClient.ProviderAPI.ListProviders(ctx).Execute() + if err != nil { + return nil, err + } + + availableProviderList, _, err := apiClient.ProviderAPI.ListProvidersForInstall(ctx).Execute() + if err != nil { + return nil, err + } + + var latestProviderList []apiclient.ProviderDTO + for _, provider := range availableProviderList { + if provider.Latest { + latestProviderList = append(latestProviderList, provider) + } + } + + providerList := installedProviderList + for _, latestProvider := range latestProviderList { + installed := false + for _, installedProvider := range installedProviderList { + if latestProvider.Name != installedProvider.Name { + continue + } + installed = true + break + } + + if !installed { + providerList = append(providerList, apiclient.ProviderInfo{ + Name: latestProvider.Name, + Version: latestProvider.Version, + Label: latestProvider.Label, + }) + } + } + + providerViewList, err := getProviderViewOptions(ctx, apiClient, providerList) + if err != nil { + return nil, err + } + + selectedProvider, err := provider_view.GetProviderFromPrompt(providerViewList, "Choose a Provider", false) + if err != nil { + if common.IsCtrlCAbort(err) { + return nil, nil + } else { + return nil, err + } + } + + if selectedProvider == nil { + return nil, nil + } + + selectedTargetConfig := &targetconfig.TargetConfigView{ + Name: "", + Options: "{}", + ProviderInfo: targetconfig.ProviderInfo{ + Name: selectedProvider.Name, + AgentlessTarget: selectedProvider.AgentlessTarget, + RunnerId: selectedProvider.RunnerId, + RunnerName: selectedProvider.RunnerName, + Version: selectedProvider.Version, + Label: selectedProvider.Label, + }, + } + + if selectedProvider.Installed != nil && !*selectedProvider.Installed { + selectedRunner, err := cmd_common.GetRunnerFlow(apiClient, "Manage Providers") + if err != nil { + if common.IsCtrlCAbort(err) { + return nil, nil + } else { + return nil, err + } + } + + if selectedRunner == nil { + return nil, nil + } + + err = provider.InstallProvider(apiClient, selectedRunner.Id, install.ProviderInstallView{ + Name: selectedProvider.Name, + Version: selectedProvider.Version, + Label: selectedProvider.Label, + }) + if err != nil { + return nil, err + } + + selectedProvider.RunnerId = selectedRunner.Id + selectedProvider.RunnerName = selectedRunner.Name + } + + targetConfigs, res, err := apiClient.TargetConfigAPI.ListTargetConfigs(ctx).Execute() + if err != nil { + return nil, apiclient_util.HandleErrorResponse(res, err) + } + selectedTargetConfig.Name = "" + err = targetconfig.NewTargetConfigNameInput(&selectedTargetConfig.Name, util.ArrayMap(targetConfigs, func(t apiclient.TargetConfig) string { + return t.Name + })) + if err != nil { + return nil, err + } + + err = targetconfig.CreateTargetConfigForm(selectedTargetConfig, selectedProvider.TargetConfigManifest) + if err != nil { + return nil, err + } + + targetConfigData := apiclient.CreateTargetConfigDTO{ + Name: selectedTargetConfig.Name, + Options: selectedTargetConfig.Options, + ProviderInfo: apiclient.ProviderInfo{ + AgentlessTarget: selectedProvider.AgentlessTarget, + Name: selectedProvider.Name, + Version: selectedProvider.Version, + Label: selectedProvider.Label, + RunnerId: selectedProvider.RunnerId, + RunnerName: selectedProvider.RunnerName, + TargetConfigManifest: selectedProvider.TargetConfigManifest, + }, + } + + targetConfig, res, err := apiClient.TargetConfigAPI.CreateTargetConfig(context.Background()).TargetConfig(targetConfigData).Execute() + if err != nil { + return nil, apiclient_util.HandleErrorResponse(res, err) + } + + return &targetconfig.TargetConfigView{ + Id: targetConfig.Id, + Name: targetConfig.Name, + Options: targetConfig.Options, + ProviderInfo: targetconfig.ProviderInfo{ + Name: targetConfig.ProviderInfo.Name, + AgentlessTarget: targetConfig.ProviderInfo.AgentlessTarget, + RunnerId: targetConfig.ProviderInfo.RunnerId, + RunnerName: targetConfig.ProviderInfo.RunnerName, + Version: targetConfig.ProviderInfo.Version, + Label: targetConfig.ProviderInfo.Label, + }, + }, nil +} + +func handleTargetConfigJSON(data []byte) error { + ctx := context.Background() + + apiClient, err := apiclient_util.GetApiClient(nil) + if err != nil { + return err + } + var selectedTargetConfig *targetconfig.TargetConfigView + err = parseJSON(data, &selectedTargetConfig) + if err != nil { + return fmt.Errorf("failed to parse input: %w", err) + } + + if selectedTargetConfig.Name == "" { + return errors.New("invalid input: 'name' field is required") + } + if selectedTargetConfig.Options == "" { + return errors.New("option fields are required to setup your target config") + } + targetManifest := selectedTargetConfig.ProviderInfo.TargetConfigManifest + + err = validateProperty(targetManifest, selectedTargetConfig) + if err != nil { + return err + } + targetConfigData := apiclient.CreateTargetConfigDTO{ + Name: selectedTargetConfig.Name, + Options: selectedTargetConfig.Options, + ProviderInfo: apiclient.ProviderInfo{ + RunnerId: selectedTargetConfig.ProviderInfo.RunnerId, + RunnerName: selectedTargetConfig.ProviderInfo.RunnerName, + Name: selectedTargetConfig.ProviderInfo.Name, + Version: selectedTargetConfig.ProviderInfo.Version, + AgentlessTarget: selectedTargetConfig.ProviderInfo.AgentlessTarget, + Label: selectedTargetConfig.ProviderInfo.Label, + TargetConfigManifest: selectedTargetConfig.ProviderInfo.TargetConfigManifest, + }, + } + targetConfig, res, err := apiClient.TargetConfigAPI.CreateTargetConfig(ctx).TargetConfig(targetConfigData).Execute() + if err != nil { + return apiclient_util.HandleErrorResponse(res, err) + } + views.RenderInfoMessage(fmt.Sprintf("Target config '%s' created successfully", targetConfig.Name)) + return nil +} + +func parseJSON(data []byte, v interface{}) error { + if err := json.Unmarshal(data, v); err == nil { + return nil + } + return errors.New("input is not a valid JSON") +} + +func validateProperty(targetManifest map[string]apiclient.TargetConfigProperty, targetConfig *targetconfig.TargetConfigView) error { + optionMap := make(map[string]interface{}) + if err := json.Unmarshal([]byte(targetConfig.Options), &optionMap); err != nil { + return fmt.Errorf("failed to parse options JSON: %w", err) + } + for optionKey := range optionMap { + if _, exists := targetManifest[optionKey]; !exists { + return fmt.Errorf("invalid property '%s' for target manifest '%s'", optionKey, targetConfig.Name) + } + } + + sortedKeys := make([]string, 0, len(targetManifest)) + for k := range targetManifest { + sortedKeys = append(sortedKeys, k) + } + sort.Strings(sortedKeys) + + for _, name := range sortedKeys { + if _, present := optionMap[name]; !present { + continue + } + + property := targetManifest[name] + if property.DisabledPredicate != nil && *property.DisabledPredicate != "" { + if matched, err := regexp.Match(*property.DisabledPredicate, []byte(targetConfig.Name)); err == nil && matched { + if !contains(property.Options, optionMap[name]) { + return fmt.Errorf("unexpected property '%s' for target manifest '%s'", name, targetConfig.Name) + } + continue + } + } + + switch *property.Type { + case apiclient.TargetConfigPropertyTypeFloat, apiclient.TargetConfigPropertyTypeInt: + _, isNumber := optionMap[name].(float64) + if !isNumber { + return fmt.Errorf("invalid type for %s, expected number", name) + } + + case apiclient.TargetConfigPropertyTypeString: + _, isString := optionMap[name].(string) + if !isString { + return fmt.Errorf("invalid type for %s, expected string", name) + } + + case apiclient.TargetConfigPropertyTypeBoolean: + _, isBool := optionMap[name].(bool) + if !isBool { + return fmt.Errorf("invalid type for %s, expected boolean", name) + } + + case apiclient.TargetConfigPropertyTypeOption: + optionValue, ok := optionMap[name].(string) + if !ok { + return fmt.Errorf("invalid value for '%s': expected a string", name) + } + valid := false + for _, allowedOption := range property.Options { + if optionValue == allowedOption { + valid = true + break + } + } + if !valid { + return fmt.Errorf("unexpected property '%s' for target manifest '%s' : valid properties are %v", optionValue, targetConfig.Name, property.Options) + } + + case apiclient.TargetConfigPropertyTypeFilePath: + _, isString := optionMap[name].(string) + if !isString { + return fmt.Errorf("invalid type for %s, expected file path string", name) + } + + default: + return fmt.Errorf("unsupported provider type: %s", *property.Type) + } + } + return nil +} + +func contains(slice []string, item interface{}) bool { + for _, val := range slice { + if val == item { + return true + } + } + return false +} + +func init() { + TargetConfigCreateCmd.Flags().StringVarP(&pipeFile, "file", "f", "", "Path to JSON file for target configuration, use '-' to read from stdin") +} + +func getProviderViewOptions(ctx context.Context, apiClient *apiclient.APIClient, latestProviders []apiclient.ProviderInfo) ([]provider_view.ProviderView, error) { + var result []provider_view.ProviderView + + installedProviders, res, err := apiClient.ProviderAPI.ListProviders(ctx).Execute() + if err != nil { + return nil, apiclient_util.HandleErrorResponse(res, err) + } + + providerMap := make(map[string]provider_view.ProviderView) + + for _, installedProvider := range installedProviders { + providerMap[installedProvider.Name] = provider_view.ProviderView{ + Name: installedProvider.Name, + AgentlessTarget: installedProvider.AgentlessTarget, + Label: installedProvider.Label, + Version: installedProvider.Version, + Installed: util.Pointer(true), + RunnerId: installedProvider.RunnerId, + RunnerName: installedProvider.RunnerName, + TargetConfigManifest: installedProvider.TargetConfigManifest, + } + } + + for _, latestProvider := range latestProviders { + if _, exists := providerMap[latestProvider.Name]; !exists { + providerMap[latestProvider.Name] = provider_view.ProviderView{ + Name: latestProvider.Name, + Label: latestProvider.Label, + Version: latestProvider.Version, + Installed: util.Pointer(false), + RunnerId: latestProvider.RunnerId, + RunnerName: latestProvider.RunnerName, + TargetConfigManifest: latestProvider.TargetConfigManifest, + } + } + } + + for _, provider := range providerMap { + result = append(result, provider) + } + + return result, nil +} diff --git a/pkg/cmd/targetconfig/delete.go b/pkg/cmd/targetconfig/delete.go new file mode 100644 index 0000000000..845a1894fe --- /dev/null +++ b/pkg/cmd/targetconfig/delete.go @@ -0,0 +1,83 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package targetconfig + +import ( + "context" + "fmt" + + "github.com/daytonaio/daytona/cmd/daytona/config" + apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" + cmd_common "github.com/daytonaio/daytona/pkg/cmd/common" + "github.com/daytonaio/daytona/pkg/common" + "github.com/daytonaio/daytona/pkg/views" + "github.com/daytonaio/daytona/pkg/views/targetconfig" + views_util "github.com/daytonaio/daytona/pkg/views/util" + "github.com/spf13/cobra" +) + +var yesFlag bool + +var deleteCmd = &cobra.Command{ + Use: "delete [TARGET_CONFIG]", + Short: "Deletes a target config", + Args: cobra.RangeArgs(0, 1), + Aliases: cmd_common.GetAliases("delete"), + RunE: func(cmd *cobra.Command, args []string) error { + var selectedConfigName string + + ctx := context.Background() + apiClient, err := apiclient_util.GetApiClient(nil) + if err != nil { + return err + } + + c, err := config.GetConfig() + if err != nil { + return err + } + + if len(args) == 0 { + activeProfile, err := c.GetActiveProfile() + if err != nil { + return err + } + + targetConfigs, res, err := apiClient.TargetConfigAPI.ListTargetConfigs(ctx).Execute() + if err != nil { + return apiclient_util.HandleErrorResponse(res, err) + } + + if len(targetConfigs) == 0 { + views_util.NotifyEmptyTargetConfigList(false) + return nil + } + + selectedTargetConfig, err := targetconfig.GetTargetConfigFromPrompt(targetConfigs, activeProfile.Name, nil, false, "Delete") + if err != nil { + if common.IsCtrlCAbort(err) { + return nil + } else { + return err + } + } + + selectedConfigName = selectedTargetConfig.Name + } else { + selectedConfigName = args[0] + } + + res, err := apiClient.TargetConfigAPI.DeleteTargetConfig(ctx, selectedConfigName).Execute() + if err != nil { + return apiclient_util.HandleErrorResponse(res, err) + } + + views.RenderInfoMessageBold(fmt.Sprintf("Target config %s removed successfully", selectedConfigName)) + return nil + }, +} + +func init() { + deleteCmd.Flags().BoolVarP(&yesFlag, "yes", "y", false, "Confirm deletion of all targets without prompt") +} diff --git a/pkg/cmd/targetconfig/list.go b/pkg/cmd/targetconfig/list.go new file mode 100644 index 0000000000..7811f34e7f --- /dev/null +++ b/pkg/cmd/targetconfig/list.go @@ -0,0 +1,50 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package targetconfig + +import ( + "context" + + apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" + "github.com/daytonaio/daytona/pkg/cmd/common" + "github.com/daytonaio/daytona/pkg/cmd/format" + "github.com/daytonaio/daytona/pkg/views/targetconfig" + "github.com/spf13/cobra" +) + +var listCmd = &cobra.Command{ + Use: "list", + Short: "List target configs", + Args: cobra.NoArgs, + Aliases: common.GetAliases("list"), + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.Background() + + apiClient, err := apiclient_util.GetApiClient(nil) + if err != nil { + return err + } + + targetConfigs, res, err := apiClient.TargetConfigAPI.ListTargetConfigs(ctx).ShowOptions(showOptions).Execute() + if err != nil { + return apiclient_util.HandleErrorResponse(res, err) + } + + if format.FormatFlag != "" { + formattedData := format.NewFormatter(targetConfigs) + formattedData.Print() + return nil + } + + targetconfig.ListTargetConfigs(targetConfigs, showOptions) + return nil + }, +} + +var showOptions bool + +func init() { + listCmd.Flags().BoolVarP(&showOptions, "show-options", "v", false, "Show target options") + format.RegisterFormatFlag(listCmd) +} diff --git a/pkg/cmd/targetconfig/target_config.go b/pkg/cmd/targetconfig/target_config.go new file mode 100644 index 0000000000..bdf5b8c640 --- /dev/null +++ b/pkg/cmd/targetconfig/target_config.go @@ -0,0 +1,23 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package targetconfig + +import ( + "github.com/daytonaio/daytona/internal/util" + "github.com/spf13/cobra" +) + +var TargetConfigCmd = &cobra.Command{ + Use: "target-config", + Short: "Manage target configs", + Args: cobra.NoArgs, + GroupID: util.SERVER_GROUP, + Aliases: []string{"target-configs", "tc"}, +} + +func init() { + TargetConfigCmd.AddCommand(listCmd) + TargetConfigCmd.AddCommand(TargetConfigCreateCmd) + TargetConfigCmd.AddCommand(deleteCmd) +} diff --git a/pkg/cmd/workspace/code.go b/pkg/cmd/workspace/code.go index 74e0fb4df3..e38e4e14bb 100644 --- a/pkg/cmd/workspace/code.go +++ b/pkg/cmd/workspace/code.go @@ -7,31 +7,29 @@ import ( "context" "errors" "fmt" + "net/http" "net/url" "strings" "github.com/daytonaio/daytona/cmd/daytona/config" - "github.com/daytonaio/daytona/internal/jetbrains" "github.com/daytonaio/daytona/internal/util" apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" "github.com/daytonaio/daytona/pkg/apiclient" - workspace_util "github.com/daytonaio/daytona/pkg/cmd/workspace/util" - "github.com/daytonaio/daytona/pkg/ide" - "github.com/daytonaio/daytona/pkg/server/workspaces" - "github.com/daytonaio/daytona/pkg/telemetry" + "github.com/daytonaio/daytona/pkg/cmd/common" + "github.com/daytonaio/daytona/pkg/cmd/workspace/create" ide_views "github.com/daytonaio/daytona/pkg/views/ide" - views_util "github.com/daytonaio/daytona/pkg/views/util" "github.com/daytonaio/daytona/pkg/views/workspace/selection" + log "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) var CodeCmd = &cobra.Command{ - Use: "code [WORKSPACE] [PROJECT]", + Use: "code [WORKSPACE]", Short: "Open a workspace in your preferred IDE", Args: cobra.RangeArgs(0, 2), Aliases: []string{"open"}, - GroupID: util.WORKSPACE_GROUP, + GroupID: util.TARGET_GROUP, RunE: func(cmd *cobra.Command, args []string) error { c, err := config.GetConfig() if err != nil { @@ -39,11 +37,9 @@ var CodeCmd = &cobra.Command{ } ctx := context.Background() - var workspaceId string - var projectName string var providerConfigId *string var ideId string - var workspace *apiclient.WorkspaceDTO + var ws *apiclient.WorkspaceDTO activeProfile, err := c.GetActiveProfile() if err != nil { @@ -58,62 +54,36 @@ var CodeCmd = &cobra.Command{ } if len(args) == 0 { - workspaceList, res, err := apiClient.WorkspaceAPI.ListWorkspaces(ctx).Verbose(true).Execute() + workspaceList, res, err := apiClient.WorkspaceAPI.ListWorkspaces(ctx).Execute() if err != nil { return apiclient_util.HandleErrorResponse(res, err) } if len(workspaceList) == 0 { - views_util.NotifyEmptyWorkspaceList(true) - return nil + return errors.New("no workspaces found") } - workspace = selection.GetWorkspaceFromPrompt(workspaceList, "Open") - if workspace == nil { + ws = selection.GetWorkspaceFromPrompt(workspaceList, "Open") + if ws == nil { return nil } - workspaceId = workspace.Id } else { - workspace, err = apiclient_util.GetWorkspace(url.PathEscape(args[0]), true) + var statusCode int + ws, statusCode, err = apiclient_util.GetWorkspace(url.PathEscape(args[0])) if err != nil { - if strings.Contains(err.Error(), workspaces.ErrWorkspaceNotFound.Error()) { + if statusCode == http.StatusNotFound { log.Debug(err) return errors.New("workspace not found. You can see all workspace names by running the command `daytona list`") } return err } - workspaceId = workspace.Id - } - - if len(args) == 0 || len(args) == 1 { - selectedProject, err := selectWorkspaceProject(workspaceId, &activeProfile) - if err != nil { - return err - } - if selectedProject == nil { - return nil - } - - projectName = selectedProject.Name - providerConfigId = selectedProject.GitProviderConfigId - } - - if len(args) == 2 { - projectName = args[1] - for _, project := range workspace.Projects { - if project.Name == projectName { - providerConfigId = project.GitProviderConfigId - break - } - } } - - if ideFlag != "" { - ideId = ideFlag + if create.IdeFlag != "" { + ideId = create.IdeFlag } - if !workspace_util.IsProjectRunning(workspace, projectName) { - wsRunningStatus, err := AutoStartWorkspace(workspace.Name, projectName) + if ws.State.Name == apiclient.ResourceStateNameStopped { + wsRunningStatus, err := AutoStartWorkspace(*ws) if err != nil { return err } @@ -122,99 +92,23 @@ var CodeCmd = &cobra.Command{ } } - providerMetadata := "" - if ideId != "ssh" { - providerMetadata, err = workspace_util.GetProjectProviderMetadata(workspace, projectName) - if err != nil { - return err - } - } + providerMetadata := *ws.ProviderMetadata - gpgKey, err := GetGitProviderGpgKey(apiClient, ctx, providerConfigId) + gpgKey, err := common.GetGitProviderGpgKey(apiClient, ctx, providerConfigId) if err != nil { log.Warn(err) } yesFlag, _ := cmd.Flags().GetBool("yes") ideList := config.GetIdeList() - ide_views.RenderIdeOpeningMessage(workspace.Name, projectName, ideId, ideList) - return openIDE(ideId, activeProfile, workspaceId, projectName, providerMetadata, yesFlag, gpgKey) + ide_views.RenderIdeOpeningMessage(ws.TargetId, ws.Name, ideId, ideList) + return common.OpenIDE(ideId, activeProfile, ws.Id, providerMetadata, yesFlag, gpgKey) }, ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - if len(args) == 1 { - return getProjectNameCompletions(cmd, args, toComplete) - } - - return getWorkspaceNameCompletions() + return common.GetWorkspaceNameCompletions() }, } -func selectWorkspaceProject(workspaceId string, profile *config.Profile) (*apiclient.Project, error) { - ctx := context.Background() - - apiClient, err := apiclient_util.GetApiClient(profile) - if err != nil { - return nil, err - } - - wsInfo, res, err := apiClient.WorkspaceAPI.GetWorkspace(ctx, workspaceId).Execute() - if err != nil { - return nil, apiclient_util.HandleErrorResponse(res, err) - } - - if len(wsInfo.Projects) > 1 { - selectedProject := selection.GetProjectFromPrompt(wsInfo.Projects, "Open") - if selectedProject == nil { - return nil, nil - } - return selectedProject, nil - } else if len(wsInfo.Projects) == 1 { - return &wsInfo.Projects[0], nil - } - - return nil, errors.New("no projects found in workspace") -} - -func openIDE(ideId string, activeProfile config.Profile, workspaceId string, projectName string, projectProviderMetadata string, yesFlag bool, gpgKey string) error { - telemetry.AdditionalData["ide"] = ideId - - switch ideId { - case "vscode": - return ide.OpenVSCode(activeProfile, workspaceId, projectName, projectProviderMetadata, gpgKey) - case "code-insiders": - return ide.OpenVSCodeInsiders(activeProfile, workspaceId, projectName, projectProviderMetadata, gpgKey) - case "ssh": - return ide.OpenTerminalSsh(activeProfile, workspaceId, projectName, gpgKey, nil) - case "browser": - return ide.OpenBrowserIDE(activeProfile, workspaceId, projectName, projectProviderMetadata, gpgKey) - case "codium": - return ide.OpenVScodium(activeProfile, workspaceId, projectName, projectProviderMetadata, gpgKey) - case "codium-insiders": - return ide.OpenVScodiumInsiders(activeProfile, workspaceId, projectName, projectProviderMetadata, gpgKey) - case "cursor": - return ide.OpenCursor(activeProfile, workspaceId, projectName, projectProviderMetadata, gpgKey) - case "jupyter": - return ide.OpenJupyterIDE(activeProfile, workspaceId, projectName, projectProviderMetadata, yesFlag, gpgKey) - case "fleet": - return ide.OpenFleet(activeProfile, workspaceId, projectName, gpgKey) - case "positron": - return ide.OpenPositron(activeProfile, workspaceId, projectName, projectProviderMetadata, gpgKey) - case "zed": - return ide.OpenZed(activeProfile, workspaceId, projectName, gpgKey) - case "windsurf": - return ide.OpenWindsurf(activeProfile, workspaceId, projectName, projectProviderMetadata, gpgKey) - default: - _, ok := jetbrains.GetIdes()[jetbrains.Id(ideId)] - if ok { - return ide.OpenJetbrainsIDE(activeProfile, ideId, workspaceId, projectName, gpgKey) - } - } - - return errors.New("invalid IDE. Please choose one by running `daytona ide`") -} - -var ideFlag string - func init() { ideList := config.GetIdeList() ids := make([]string, len(ideList)) @@ -222,15 +116,15 @@ func init() { ids[i] = ide.Id } ideListStr := strings.Join(ids, ", ") - CodeCmd.Flags().StringVarP(&ideFlag, "ide", "i", "", fmt.Sprintf("Specify the IDE (%s)", ideListStr)) + CodeCmd.Flags().StringVarP(&create.IdeFlag, "ide", "i", "", fmt.Sprintf("Specify the IDE (%s)", ideListStr)) CodeCmd.Flags().BoolVarP(&yesFlag, "yes", "y", false, "Automatically confirm any prompts") } -func AutoStartWorkspace(workspaceId string, projectName string) (bool, error) { +func AutoStartWorkspace(workspace apiclient.WorkspaceDTO) (bool, error) { if !yesFlag { - if !ide_views.RunStartWorkspaceForm(workspaceId) { + if !ide_views.RunStartWorkspaceForm(workspace.Name) { return false, nil } } @@ -240,7 +134,7 @@ func AutoStartWorkspace(workspaceId string, projectName string) (bool, error) { return false, err } - err = StartWorkspace(apiClient, workspaceId, projectName) + err = StartWorkspace(apiClient, workspace, false) if err != nil { return false, err } diff --git a/pkg/cmd/workspace/create.go b/pkg/cmd/workspace/create.go deleted file mode 100644 index c9f7276274..0000000000 --- a/pkg/cmd/workspace/create.go +++ /dev/null @@ -1,568 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package workspace - -import ( - "context" - "errors" - "fmt" - "net/http" - "net/url" - "os/exec" - "strings" - "time" - - "github.com/daytonaio/daytona/internal/cmd/tailscale" - "github.com/daytonaio/daytona/internal/util" - apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" - ssh_config "github.com/daytonaio/daytona/pkg/agent/ssh/config" - "github.com/daytonaio/daytona/pkg/apiclient" - workspace_util "github.com/daytonaio/daytona/pkg/cmd/workspace/util" - "github.com/daytonaio/daytona/pkg/common" - "github.com/daytonaio/daytona/pkg/gitprovider" - "github.com/daytonaio/daytona/pkg/logs" - "github.com/daytonaio/daytona/pkg/views" - logs_view "github.com/daytonaio/daytona/pkg/views/logs" - views_util "github.com/daytonaio/daytona/pkg/views/util" - "github.com/daytonaio/daytona/pkg/views/workspace/create" - "github.com/daytonaio/daytona/pkg/views/workspace/info" - "github.com/daytonaio/daytona/pkg/views/workspace/selection" - "github.com/daytonaio/daytona/pkg/workspace/project" - "github.com/docker/docker/pkg/stringid" - log "github.com/sirupsen/logrus" - "tailscale.com/tsnet" - - "github.com/spf13/cobra" - - "github.com/daytonaio/daytona/cmd/daytona/config" -) - -var CreateCmd = &cobra.Command{ - Use: "create [REPOSITORY_URL | PROJECT_CONFIG_NAME]...", - Short: "Create a workspace", - GroupID: util.WORKSPACE_GROUP, - RunE: func(cmd *cobra.Command, args []string) error { - ctx := context.Background() - var projects []apiclient.CreateProjectDTO - var workspaceName string - var existingWorkspaceNames []string - var existingProjectConfigNames []string - promptUsingTUI := len(args) == 0 - - apiClient, err := apiclient_util.GetApiClient(nil) - if err != nil { - return err - } - - c, err := config.GetConfig() - if err != nil { - return err - } - - activeProfile, err := c.GetActiveProfile() - if err != nil { - return err - } - - profileData, res, err := apiClient.ProfileAPI.GetProfileData(ctx).Execute() - if err != nil { - return apiclient_util.HandleErrorResponse(res, err) - } - - if nameFlag != "" { - workspaceName = nameFlag - } - - workspaceList, res, err := apiClient.WorkspaceAPI.ListWorkspaces(ctx).Execute() - if err != nil { - return apiclient_util.HandleErrorResponse(res, err) - } - for _, workspaceInfo := range workspaceList { - existingWorkspaceNames = append(existingWorkspaceNames, workspaceInfo.Name) - } - - if promptUsingTUI { - err = processPrompting(ctx, apiClient, &workspaceName, &projects, existingWorkspaceNames) - if err != nil { - if common.IsCtrlCAbort(err) { - return nil - } else { - return err - } - } - } else { - existingProjectConfigNames, err = processCmdArguments(ctx, args, apiClient, &projects) - if err != nil { - return err - } - - initialSuggestion := projects[0].Name - - if workspaceName == "" { - workspaceName = workspace_util.GetSuggestedName(initialSuggestion, existingWorkspaceNames) - } - } - - if workspaceName == "" || len(projects) == 0 { - return errors.New("workspace name and repository urls are required") - } - - projectNames := []string{} - for i := range projects { - if profileData != nil && profileData.EnvVars != nil { - projects[i].EnvVars = util.MergeEnvVars(profileData.EnvVars, projects[i].EnvVars) - } else { - projects[i].EnvVars = util.MergeEnvVars(projects[i].EnvVars) - } - projectNames = append(projectNames, projects[i].Name) - } - - for i, projectConfigName := range existingProjectConfigNames { - if projectConfigName == "" { - continue - } - logs_view.DisplayLogEntry(logs.LogEntry{ - ProjectName: &projects[i].Name, - Msg: fmt.Sprintf("Using detected project config '%s'\n", projectConfigName), - }, i) - } - - targetList, res, err := apiClient.TargetAPI.ListTargets(ctx).Execute() - if err != nil { - return apiclient_util.HandleErrorResponse(res, err) - } - - target, err := workspace_util.GetTarget(workspace_util.GetTargetConfig{ - Ctx: ctx, - ApiClient: apiClient, - TargetList: targetList, - ActiveProfileName: activeProfile.Name, - TargetNameFlag: targetNameFlag, - PromptUsingTUI: promptUsingTUI, - }) - if err != nil { - if common.IsCtrlCAbort(err) { - return nil - } - return err - } - - logs_view.CalculateLongestPrefixLength(projectNames) - - logs_view.DisplayLogEntry(logs.LogEntry{ - Msg: "Request submitted\n", - }, logs_view.STATIC_INDEX) - - activeProfile, err = c.GetActiveProfile() - if err != nil { - return err - } - - var tsConn *tsnet.Server - if target.Name != "local" || activeProfile.Id != "default" { - tsConn, err = tailscale.GetConnection(&activeProfile) - if err != nil { - return err - } - } - - id := stringid.GenerateRandomID() - id = stringid.TruncateID(id) - - logsContext, stopLogs := context.WithCancel(context.Background()) - go apiclient_util.ReadWorkspaceLogs(logsContext, activeProfile, id, projectNames, true, true, nil) - - createdWorkspace, res, err := apiClient.WorkspaceAPI.CreateWorkspace(ctx).Workspace(apiclient.CreateWorkspaceDTO{ - Id: id, - Name: workspaceName, - Target: target.Name, - Projects: projects, - }).Execute() - if err != nil { - stopLogs() - return apiclient_util.HandleErrorResponse(res, err) - } - gpgKey, err := GetGitProviderGpgKey(apiClient, ctx, projects[0].GitProviderConfigId) - if err != nil { - log.Warn(err) - } - - err = waitForDial(createdWorkspace, &activeProfile, tsConn, gpgKey) - if err != nil { - stopLogs() - return err - } - - stopLogs() - - // Make sure terminal cursor is reset - fmt.Print("\033[?25h") - - wsInfo, res, err := apiClient.WorkspaceAPI.GetWorkspace(ctx, workspaceName).Verbose(true).Execute() - if err != nil { - return apiclient_util.HandleErrorResponse(res, err) - } - - chosenIdeId := c.DefaultIdeId - if ideFlag != "" { - chosenIdeId = ideFlag - } - - ideList := config.GetIdeList() - var chosenIde config.Ide - - for _, ide := range ideList { - if ide.Id == chosenIdeId { - chosenIde = ide - } - } - - fmt.Println() - info.Render(wsInfo, chosenIde.Name, false) - - if noIdeFlag { - views.RenderCreationInfoMessage("Run 'daytona code' when you're ready to start developing") - return nil - } - - views.RenderCreationInfoMessage(fmt.Sprintf("Opening the workspace in %s ...", chosenIde.Name)) - - projectName := wsInfo.Projects[0].Name - providerMetadata, err := workspace_util.GetProjectProviderMetadata(wsInfo, projectName) - if err != nil { - return err - } - - return openIDE(chosenIdeId, activeProfile, createdWorkspace.Id, wsInfo.Projects[0].Name, providerMetadata, yesFlag, gpgKey) - }, -} - -var nameFlag string -var targetNameFlag string -var noIdeFlag bool -var blankFlag bool -var multiProjectFlag bool - -var projectConfigurationFlags = workspace_util.ProjectConfigurationFlags{ - Builder: new(views_util.BuildChoice), - CustomImage: new(string), - CustomImageUser: new(string), - Branches: new([]string), - DevcontainerPath: new(string), - EnvVars: new([]string), - Manual: new(bool), - GitProviderConfig: new(string), -} - -func init() { - ideList := config.GetIdeList() - ids := make([]string, len(ideList)) - for i, ide := range ideList { - ids[i] = ide.Id - } - ideListStr := strings.Join(ids, ", ") - - CreateCmd.Flags().StringVar(&nameFlag, "name", "", "Specify the workspace name") - CreateCmd.Flags().StringVarP(&ideFlag, "ide", "i", "", fmt.Sprintf("Specify the IDE (%s)", ideListStr)) - CreateCmd.Flags().StringVarP(&targetNameFlag, "target", "t", "", "Specify the target (e.g. 'local')") - CreateCmd.Flags().BoolVar(&blankFlag, "blank", false, "Create a blank project without using existing configurations") - CreateCmd.Flags().BoolVarP(&noIdeFlag, "no-ide", "n", false, "Do not open the workspace in the IDE after workspace creation") - CreateCmd.Flags().BoolVar(&multiProjectFlag, "multi-project", false, "Workspace with multiple projects/repos") - CreateCmd.Flags().BoolVarP(&yesFlag, "yes", "y", false, "Automatically confirm any prompts") - CreateCmd.Flags().StringSliceVar(projectConfigurationFlags.Branches, "branch", []string{}, "Specify the Git branches to use in the projects") - - workspace_util.AddProjectConfigurationFlags(CreateCmd, projectConfigurationFlags, true) -} - -func processPrompting(ctx context.Context, apiClient *apiclient.APIClient, workspaceName *string, projects *[]apiclient.CreateProjectDTO, workspaceNames []string) error { - if workspace_util.CheckAnyProjectConfigurationFlagSet(projectConfigurationFlags) || (projectConfigurationFlags.Branches != nil && len(*projectConfigurationFlags.Branches) > 0) { - return errors.New("please provide the repository URL in order to set up custom project details through the CLI") - } - - gitProviders, res, err := apiClient.GitProviderAPI.ListGitProviders(ctx).Execute() - if err != nil { - return apiclient_util.HandleErrorResponse(res, err) - } - - projectConfigs, res, err := apiClient.ProjectConfigAPI.ListProjectConfigs(ctx).Execute() - if err != nil { - return apiclient_util.HandleErrorResponse(res, err) - } - - apiServerConfig, res, err := apiClient.ServerAPI.GetConfig(context.Background()).Execute() - if err != nil { - return apiclient_util.HandleErrorResponse(res, err) - } - - projectDefaults := &views_util.ProjectConfigDefaults{ - BuildChoice: views_util.AUTOMATIC, - Image: &apiServerConfig.DefaultProjectImage, - ImageUser: &apiServerConfig.DefaultProjectUser, - DevcontainerFilePath: create.DEVCONTAINER_FILEPATH, - } - - *projects, err = workspace_util.GetProjectsCreationDataFromPrompt(workspace_util.ProjectsDataPromptConfig{ - UserGitProviders: gitProviders, - ProjectConfigs: projectConfigs, - Manual: *projectConfigurationFlags.Manual, - MultiProject: multiProjectFlag, - BlankProject: blankFlag, - ApiClient: apiClient, - Defaults: projectDefaults, - }) - - if err != nil { - return err - } - - initialSuggestion := (*projects)[0].Name - - suggestedName := workspace_util.GetSuggestedName(initialSuggestion, workspaceNames) - - dedupProjectNames(projects) - - submissionFormConfig := create.SubmissionFormConfig{ - ChosenName: workspaceName, - SuggestedName: suggestedName, - ExistingNames: workspaceNames, - ProjectList: projects, - NameLabel: "Workspace", - Defaults: projectDefaults, - } - - pcImportFlag := false - err = create.RunSubmissionForm(submissionFormConfig, &pcImportFlag) - if err != nil { - return err - } - - return nil -} - -func processCmdArguments(ctx context.Context, repoUrls []string, apiClient *apiclient.APIClient, projects *[]apiclient.CreateProjectDTO) ([]string, error) { - if len(repoUrls) == 0 { - return nil, fmt.Errorf("no repository URLs provided") - } - - if len(repoUrls) > 1 && workspace_util.CheckAnyProjectConfigurationFlagSet(projectConfigurationFlags) { - return nil, fmt.Errorf("can't set custom project configuration properties for multiple projects") - } - - if *projectConfigurationFlags.Builder != "" && *projectConfigurationFlags.Builder != views_util.DEVCONTAINER && *projectConfigurationFlags.DevcontainerPath != "" { - return nil, fmt.Errorf("can't set devcontainer file path if builder is not set to %s", views_util.DEVCONTAINER) - } - - var projectConfig *apiclient.ProjectConfig - - existingProjectConfigNames := []string{} - - for i, repoUrl := range repoUrls { - var branch *string - if len(*projectConfigurationFlags.Branches) > i { - branch = &(*projectConfigurationFlags.Branches)[i] - } - - validatedUrl, err := util.GetValidatedUrl(repoUrl) - if err == nil { - // The argument is a Git URL - existingProjectConfigName, err := processGitURL(ctx, validatedUrl, apiClient, projects, branch) - if err != nil { - return nil, err - } - if existingProjectConfigName != nil { - existingProjectConfigNames = append(existingProjectConfigNames, *existingProjectConfigName) - } else { - existingProjectConfigNames = append(existingProjectConfigNames, "") - } - - continue - } - - // The argument is not a Git URL - try getting the project config - projectConfig, _, err = apiClient.ProjectConfigAPI.GetProjectConfig(ctx, repoUrl).Execute() - if err != nil { - return nil, fmt.Errorf("failed to parse the URL or fetch the project config for '%s'", repoUrl) - } - - existingProjectConfigName, err := workspace_util.AddProjectFromConfig(projectConfig, apiClient, projects, branch) - if err != nil { - return nil, err - } - if existingProjectConfigName != nil { - existingProjectConfigNames = append(existingProjectConfigNames, *existingProjectConfigName) - } else { - existingProjectConfigNames = append(existingProjectConfigNames, "") - } - } - - dedupProjectNames(projects) - - return existingProjectConfigNames, nil -} - -func processGitURL(ctx context.Context, repoUrl string, apiClient *apiclient.APIClient, projects *[]apiclient.CreateProjectDTO, branch *string) (*string, error) { - encodedURLParam := url.QueryEscape(repoUrl) - - if !blankFlag { - projectConfig, res, err := apiClient.ProjectConfigAPI.GetDefaultProjectConfig(ctx, encodedURLParam).Execute() - if err == nil { - projectConfig.GitProviderConfigId = projectConfigurationFlags.GitProviderConfig - return workspace_util.AddProjectFromConfig(projectConfig, apiClient, projects, branch) - } - - if res.StatusCode != http.StatusNotFound { - return nil, apiclient_util.HandleErrorResponse(res, err) - } - } - - repo, res, err := apiClient.GitProviderAPI.GetGitContext(ctx).Repository(apiclient.GetRepositoryContext{ - Url: repoUrl, - Branch: branch, - }).Execute() - if err != nil { - return nil, apiclient_util.HandleErrorResponse(res, err) - } - - projectName, err := workspace_util.GetSanitizedProjectName(repo.Name) - if err != nil { - return nil, err - } - - projectConfigurationFlags.GitProviderConfig, err = workspace_util.GetGitProviderConfigIdFromFlag(ctx, apiClient, projectConfigurationFlags.GitProviderConfig) - if err != nil { - return nil, err - } - - if projectConfigurationFlags.GitProviderConfig == nil || *projectConfigurationFlags.GitProviderConfig == "" { - gitProviderConfigs, res, err := apiClient.GitProviderAPI.ListGitProvidersForUrl(context.Background(), url.QueryEscape(repoUrl)).Execute() - if err != nil { - return nil, apiclient_util.HandleErrorResponse(res, err) - } - - if len(gitProviderConfigs) == 1 { - projectConfigurationFlags.GitProviderConfig = &gitProviderConfigs[0].Id - } else if len(gitProviderConfigs) > 1 { - gp := selection.GetGitProviderConfigFromPrompt(selection.GetGitProviderConfigParams{ - GitProviderConfigs: gitProviderConfigs, - ActionVerb: "Use", - }) - if gp == nil { - return nil, common.ErrCtrlCAbort - } - projectConfigurationFlags.GitProviderConfig = &gp.Id - } - } - - project, err := workspace_util.GetCreateProjectDtoFromFlags(projectConfigurationFlags) - if err != nil { - return nil, err - } - - project.Name = projectName - project.Source = apiclient.CreateProjectSourceDTO{ - Repository: *repo, - } - - *projects = append(*projects, *project) - - return nil, nil -} - -func waitForDial(workspace *apiclient.Workspace, activeProfile *config.Profile, tsConn *tsnet.Server, gpgKey string) error { - if workspace.Target == "local" && (activeProfile != nil && activeProfile.Id == "default") { - err := config.EnsureSshConfigEntryAdded(activeProfile.Id, workspace.Id, workspace.Projects[0].Name, gpgKey) - if err != nil { - return err - } - - projectHostname := config.GetProjectHostname(activeProfile.Id, workspace.Id, workspace.Projects[0].Name) - - for { - sshCommand := exec.Command("ssh", projectHostname, "daytona", "version") - sshCommand.Stdin = nil - sshCommand.Stdout = nil - sshCommand.Stderr = &util.TraceLogWriter{} - - err = sshCommand.Run() - if err == nil { - return nil - } - - time.Sleep(100 * time.Millisecond) - } - } - - connectChan := make(chan error) - spinner := time.After(15 * time.Second) - timeout := time.After(2 * time.Minute) - - go func() { - for { - dialConn, err := tsConn.Dial(context.Background(), "tcp", fmt.Sprintf("%s:%d", project.GetProjectHostname(workspace.Id, workspace.Projects[0].Name), ssh_config.SSH_PORT)) - if err == nil { - connectChan <- dialConn.Close() - return - } - time.Sleep(100 * time.Millisecond) - } - }() - - select { - case err := <-connectChan: - return err - case <-spinner: - err := views_util.WithInlineSpinner("Connection to tailscale is taking longer than usual", func() error { - select { - case err := <-connectChan: - return err - case <-timeout: - return errors.New("secure connection to the Daytona Server could not be established. Please check your internet connection or Tailscale availability") - } - }) - return err - } -} - -func dedupProjectNames(projects *[]apiclient.CreateProjectDTO) { - projectNames := map[string]int{} - - for i, project := range *projects { - if _, ok := projectNames[project.Name]; ok { - (*projects)[i].Name = fmt.Sprintf("%s-%d", project.Name, projectNames[project.Name]) - projectNames[project.Name]++ - } else { - projectNames[project.Name] = 2 - } - } -} - -func GetGitProviderGpgKey(apiClient *apiclient.APIClient, ctx context.Context, providerConfigId *string) (string, error) { - if providerConfigId == nil || *providerConfigId == "" { - return "", nil - } - - var providerConfig *gitprovider.GitProviderConfig - var gpgKey string - - gitProvider, res, err := apiClient.GitProviderAPI.GetGitProvider(ctx, *providerConfigId).Execute() - if err != nil { - return "", apiclient_util.HandleErrorResponse(res, err) - } - - // Extract GPG key if present - if gitProvider != nil { - providerConfig = &gitprovider.GitProviderConfig{ - SigningMethod: (*gitprovider.SigningMethod)(gitProvider.SigningMethod), - SigningKey: gitProvider.SigningKey, - } - - if providerConfig.SigningMethod != nil && providerConfig.SigningKey != nil { - if *providerConfig.SigningMethod == gitprovider.SigningMethodGPG { - gpgKey = *providerConfig.SigningKey - } - } - } - - return gpgKey, nil -} diff --git a/pkg/cmd/workspace/create/add_from_template.go b/pkg/cmd/workspace/create/add_from_template.go new file mode 100644 index 0000000000..30b8f82421 --- /dev/null +++ b/pkg/cmd/workspace/create/add_from_template.go @@ -0,0 +1,62 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package create + +import ( + "context" + + apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" + "github.com/daytonaio/daytona/pkg/apiclient" + "github.com/daytonaio/daytona/pkg/common" +) + +type AddWorkspaceFromTemplateParams struct { + WorkspaceTemplate *apiclient.WorkspaceTemplate + ApiClient *apiclient.APIClient + Workspaces *[]apiclient.CreateWorkspaceDTO + BranchFlag *string +} + +func AddWorkspaceFromTemplate(ctx context.Context, params AddWorkspaceFromTemplateParams) (*string, error) { + chosenBranchName := "" + if params.BranchFlag != nil { + chosenBranchName = *params.BranchFlag + } + + if chosenBranchName == "" { + chosenBranch, err := GetBranchFromWorkspaceTemplate(ctx, params.WorkspaceTemplate, params.ApiClient, 0) + if err != nil { + return nil, err + } + if chosenBranch == nil { + return nil, common.ErrCtrlCAbort + } + + chosenBranchName = chosenBranch.Name + } + + templateRepo, res, err := params.ApiClient.GitProviderAPI.GetGitContext(ctx).Repository(apiclient.GetRepositoryContext{ + Url: params.WorkspaceTemplate.RepositoryUrl, + Branch: &chosenBranchName, + }).Execute() + if err != nil { + return nil, apiclient_util.HandleErrorResponse(res, err) + } + + workspace := &apiclient.CreateWorkspaceDTO{ + Name: params.WorkspaceTemplate.Name, + GitProviderConfigId: params.WorkspaceTemplate.GitProviderConfigId, + Source: apiclient.CreateWorkspaceSourceDTO{ + Repository: *templateRepo, + }, + BuildConfig: params.WorkspaceTemplate.BuildConfig, + Image: ¶ms.WorkspaceTemplate.Image, + User: ¶ms.WorkspaceTemplate.User, + EnvVars: params.WorkspaceTemplate.EnvVars, + Labels: params.WorkspaceTemplate.Labels, + } + *params.Workspaces = append(*params.Workspaces, *workspace) + + return ¶ms.WorkspaceTemplate.Name, nil +} diff --git a/pkg/cmd/workspace/util/branch_wizard.go b/pkg/cmd/workspace/create/branch_wizard.go similarity index 66% rename from pkg/cmd/workspace/util/branch_wizard.go rename to pkg/cmd/workspace/create/branch_wizard.go index 4c0a26c958..50092d11c6 100644 --- a/pkg/cmd/workspace/util/branch_wizard.go +++ b/pkg/cmd/workspace/create/branch_wizard.go @@ -1,7 +1,7 @@ // Copyright 2024 Daytona Platforms Inc. // SPDX-License-Identifier: Apache-2.0 -package util +package create import ( "context" @@ -13,79 +13,21 @@ import ( "github.com/daytonaio/daytona/pkg/apiclient" "github.com/daytonaio/daytona/pkg/common" "github.com/daytonaio/daytona/pkg/views" + "github.com/daytonaio/daytona/pkg/views/selection" views_util "github.com/daytonaio/daytona/pkg/views/util" - "github.com/daytonaio/daytona/pkg/views/workspace/selection" ) -type BranchWizardConfig struct { +type BranchWizardParams struct { ApiClient *apiclient.APIClient GitProviderConfigId string NamespaceId string Namespace string ChosenRepo *apiclient.GitRepository - ProjectOrder int + WorkspaceOrder int ProviderId string } -func runGetBranchFromPromptWithPagination(ctx context.Context, config BranchWizardConfig, parentIdentifier string, page, perPage int32) (*apiclient.GitRepository, error) { - var branchList []apiclient.GitBranch - disablePagination := false - curPageItemsNum := 0 - selectionListCursorIdx := 0 - var selectionListOptions views.SelectionListOptions - var err error - - for { - err = views_util.WithSpinner("Loading Branches", func() error { - branches, _, err := config.ApiClient.GitProviderAPI.GetRepoBranches(ctx, config.GitProviderConfigId, url.QueryEscape(config.NamespaceId), url.QueryEscape(config.ChosenRepo.Id)).Page(page).PerPage(perPage).Execute() - if err != nil { - return err - } - - curPageItemsNum = len(branches) - branchList = append(branchList, branches...) - return nil - }) - - if err != nil { - return nil, err - } - - // Check first if the git provider supports pagination - if isGitProviderWithUnsupportedPagination(config.GitProviderConfigId) { - disablePagination = true - } else { - // Check if we have reached the end of the list - disablePagination = int32(curPageItemsNum) < perPage - } - - selectionListCursorIdx = (int)(page-1) * int(perPage) - selectionListOptions = views.SelectionListOptions{ - ParentIdentifier: parentIdentifier, - IsPaginationDisabled: disablePagination, - CursorIndex: selectionListCursorIdx, - } - - // User will either choose a branch or navigate the pages - branch, navigate := selection.GetBranchFromPrompt(branchList, config.ProjectOrder, selectionListOptions) - if !disablePagination && navigate != "" { - if navigate == views.ListNavigationText { - page++ - continue // Fetch the next page of branches - } - } else if branch != nil { - config.ChosenRepo.Branch = branch.Name - config.ChosenRepo.Sha = branch.Sha - - return config.ChosenRepo, nil - } else { - // If user aborts or there's no selection - return nil, errors.New("must select a branch") - } - } -} - -func SetBranchFromWizard(config BranchWizardConfig) (*apiclient.GitRepository, error) { +func SetBranchFromWizard(params BranchWizardParams) (*apiclient.GitRepository, error) { var branchList []apiclient.GitBranch var checkoutOptions []selection.CheckoutOption page := int32(1) @@ -95,7 +37,7 @@ func SetBranchFromWizard(config BranchWizardConfig) (*apiclient.GitRepository, e ctx := context.Background() err = views_util.WithSpinner("Loading", func() error { - branches, _, err := config.ApiClient.GitProviderAPI.GetRepoBranches(ctx, config.GitProviderConfigId, url.QueryEscape(config.NamespaceId), url.QueryEscape(config.ChosenRepo.Id)).Page(page).PerPage(perPage).Execute() + branches, _, err := params.ApiClient.GitProviderAPI.GetRepoBranches(ctx, params.GitProviderConfigId, url.QueryEscape(params.NamespaceId), url.QueryEscape(params.ChosenRepo.Id)).Page(page).PerPage(perPage).Execute() if err != nil { return err } @@ -113,9 +55,9 @@ func SetBranchFromWizard(config BranchWizardConfig) (*apiclient.GitRepository, e } if len(branchList) == 1 { - config.ChosenRepo.Branch = branchList[0].Name - config.ChosenRepo.Sha = branchList[0].Sha - return config.ChosenRepo, nil + params.ChosenRepo.Branch = branchList[0].Name + params.ChosenRepo.Sha = branchList[0].Sha + return params.ChosenRepo, nil } var prList []apiclient.GitPullRequest @@ -124,7 +66,7 @@ func SetBranchFromWizard(config BranchWizardConfig) (*apiclient.GitRepository, e perPage = 1 err = views_util.WithSpinner("Loading", func() error { - prs, _, err := config.ApiClient.GitProviderAPI.GetRepoPRs(ctx, config.GitProviderConfigId, url.QueryEscape(config.NamespaceId), url.QueryEscape(config.ChosenRepo.Id)).Page(page).PerPage(perPage).Execute() + prs, _, err := params.ApiClient.GitProviderAPI.GetRepoPRs(ctx, params.GitProviderConfigId, url.QueryEscape(params.NamespaceId), url.QueryEscape(params.ChosenRepo.Id)).Page(page).PerPage(perPage).Execute() if err != nil { return err } @@ -137,20 +79,20 @@ func SetBranchFromWizard(config BranchWizardConfig) (*apiclient.GitRepository, e return nil, err } - namespace := config.Namespace + namespace := params.Namespace if namespace == "" { - namespace = config.ChosenRepo.Owner + namespace = params.ChosenRepo.Owner } - parentIdentifier := fmt.Sprintf("%s/%s/%s", config.ProviderId, namespace, config.ChosenRepo.Name) + parentIdentifier := fmt.Sprintf("%s/%s/%s", params.ProviderId, namespace, params.ChosenRepo.Name) if len(prList) == 0 { - return runGetBranchFromPromptWithPagination(ctx, config, parentIdentifier, 1, 100) + return runGetBranchFromPromptWithPagination(ctx, params, parentIdentifier, 1, 100) } checkoutOptions = append(checkoutOptions, selection.CheckoutDefault) checkoutOptions = append(checkoutOptions, selection.CheckoutBranch) checkoutOptions = append(checkoutOptions, selection.CheckoutPR) - chosenCheckoutOption := selection.GetCheckoutOptionFromPrompt(config.ProjectOrder, checkoutOptions, parentIdentifier) + chosenCheckoutOption := selection.GetCheckoutOptionFromPrompt(params.WorkspaceOrder, checkoutOptions, parentIdentifier) if chosenCheckoutOption == (selection.CheckoutOption{}) { return nil, common.ErrCtrlCAbort @@ -158,20 +100,20 @@ func SetBranchFromWizard(config BranchWizardConfig) (*apiclient.GitRepository, e if chosenCheckoutOption == selection.CheckoutDefault { // Get the default branch from context - repo, res, err := config.ApiClient.GitProviderAPI.GetGitContext(ctx).Repository(apiclient.GetRepositoryContext{ - Url: config.ChosenRepo.Url, + repo, res, err := params.ApiClient.GitProviderAPI.GetGitContext(ctx).Repository(apiclient.GetRepositoryContext{ + Url: params.ChosenRepo.Url, }).Execute() if err != nil { return nil, apiclient_util.HandleErrorResponse(res, err) } - config.ChosenRepo.Branch = repo.Branch + params.ChosenRepo.Branch = repo.Branch - return config.ChosenRepo, nil + return params.ChosenRepo, nil } if chosenCheckoutOption == selection.CheckoutBranch { - return runGetBranchFromPromptWithPagination(ctx, config, parentIdentifier, 1, 100) + return runGetBranchFromPromptWithPagination(ctx, params, parentIdentifier, 1, 100) } else if chosenCheckoutOption == selection.CheckoutPR { page = 1 perPage = 100 @@ -183,7 +125,7 @@ func SetBranchFromWizard(config BranchWizardConfig) (*apiclient.GitRepository, e for { err = views_util.WithSpinner("Loading Pull Requests", func() error { - prs, _, err := config.ApiClient.GitProviderAPI.GetRepoPRs(ctx, config.GitProviderConfigId, url.QueryEscape(config.NamespaceId), url.QueryEscape(config.ChosenRepo.Id)).Page(page).PerPage(perPage).Execute() + prs, _, err := params.ApiClient.GitProviderAPI.GetRepoPRs(ctx, params.GitProviderConfigId, url.QueryEscape(params.NamespaceId), url.QueryEscape(params.ChosenRepo.Id)).Page(page).PerPage(perPage).Execute() if err != nil { return err } @@ -198,7 +140,7 @@ func SetBranchFromWizard(config BranchWizardConfig) (*apiclient.GitRepository, e } // Check first if the git provider supports pagination - if isGitProviderWithUnsupportedPagination(config.ProviderId) { + if isGitProviderWithUnsupportedPagination(params.ProviderId) { disablePagination = true } else { // Check if we have reached the end of the list @@ -213,21 +155,21 @@ func SetBranchFromWizard(config BranchWizardConfig) (*apiclient.GitRepository, e } // User will either choose a PR or navigate the pages - chosenPullRequest, navigate := selection.GetPullRequestFromPrompt(prList, config.ProjectOrder, selectionListOptions) + chosenPullRequest, navigate := selection.GetPullRequestFromPrompt(prList, params.WorkspaceOrder, selectionListOptions) if !disablePagination && navigate != "" { if navigate == views.ListNavigationText { page++ continue } } else if chosenPullRequest != nil { - config.ChosenRepo.Branch = chosenPullRequest.Branch - config.ChosenRepo.Sha = chosenPullRequest.Sha - config.ChosenRepo.Id = chosenPullRequest.SourceRepoId - config.ChosenRepo.Name = chosenPullRequest.SourceRepoName - config.ChosenRepo.Owner = chosenPullRequest.SourceRepoOwner - config.ChosenRepo.Url = chosenPullRequest.SourceRepoUrl - - return config.ChosenRepo, nil + params.ChosenRepo.Branch = chosenPullRequest.Branch + params.ChosenRepo.Sha = chosenPullRequest.Sha + params.ChosenRepo.Id = chosenPullRequest.SourceRepoId + params.ChosenRepo.Name = chosenPullRequest.SourceRepoName + params.ChosenRepo.Owner = chosenPullRequest.SourceRepoOwner + params.ChosenRepo.Url = chosenPullRequest.SourceRepoUrl + + return params.ChosenRepo, nil } else { // If user aborts or there's no selection return nil, errors.New("must select a pull request") @@ -235,5 +177,63 @@ func SetBranchFromWizard(config BranchWizardConfig) (*apiclient.GitRepository, e } } - return config.ChosenRepo, nil + return params.ChosenRepo, nil +} + +func runGetBranchFromPromptWithPagination(ctx context.Context, params BranchWizardParams, parentIdentifier string, page, perPage int32) (*apiclient.GitRepository, error) { + var branchList []apiclient.GitBranch + disablePagination := false + curPageItemsNum := 0 + selectionListCursorIdx := 0 + var selectionListOptions views.SelectionListOptions + var err error + + for { + err = views_util.WithSpinner("Loading Branches", func() error { + branches, _, err := params.ApiClient.GitProviderAPI.GetRepoBranches(ctx, params.GitProviderConfigId, url.QueryEscape(params.NamespaceId), url.QueryEscape(params.ChosenRepo.Id)).Page(page).PerPage(perPage).Execute() + if err != nil { + return err + } + + curPageItemsNum = len(branches) + branchList = append(branchList, branches...) + return nil + }) + + if err != nil { + return nil, err + } + + // Check first if the git provider supports pagination + if isGitProviderWithUnsupportedPagination(params.GitProviderConfigId) { + disablePagination = true + } else { + // Check if we have reached the end of the list + disablePagination = int32(curPageItemsNum) < perPage + } + + selectionListCursorIdx = (int)(page-1) * int(perPage) + selectionListOptions = views.SelectionListOptions{ + ParentIdentifier: parentIdentifier, + IsPaginationDisabled: disablePagination, + CursorIndex: selectionListCursorIdx, + } + + // User will either choose a branch or navigate the pages + branch, navigate := selection.GetBranchFromPrompt(branchList, params.WorkspaceOrder, selectionListOptions) + if !disablePagination && navigate != "" { + if navigate == views.ListNavigationText { + page++ + continue // Fetch the next page of branches + } + } else if branch != nil { + params.ChosenRepo.Branch = branch.Name + params.ChosenRepo.Sha = branch.Sha + + return params.ChosenRepo, nil + } else { + // If user aborts or there's no selection + return nil, errors.New("must select a branch") + } + } } diff --git a/pkg/cmd/workspace/create/cmd.go b/pkg/cmd/workspace/create/cmd.go new file mode 100644 index 0000000000..68f7afc15f --- /dev/null +++ b/pkg/cmd/workspace/create/cmd.go @@ -0,0 +1,370 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package create + +import ( + "context" + "errors" + "fmt" + "os/exec" + "strings" + "time" + + "github.com/daytonaio/daytona/internal/cmd/tailscale" + "github.com/daytonaio/daytona/internal/util" + apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" + ssh_config "github.com/daytonaio/daytona/pkg/agent/ssh/config" + "github.com/daytonaio/daytona/pkg/apiclient" + cmd_common "github.com/daytonaio/daytona/pkg/cmd/common" + "github.com/daytonaio/daytona/pkg/common" + "github.com/daytonaio/daytona/pkg/logs" + "github.com/daytonaio/daytona/pkg/views" + logs_view "github.com/daytonaio/daytona/pkg/views/logs" + views_util "github.com/daytonaio/daytona/pkg/views/util" + "github.com/daytonaio/daytona/pkg/views/workspace/info" + log "github.com/sirupsen/logrus" + "tailscale.com/tsnet" + + "github.com/spf13/cobra" + + "github.com/daytonaio/daytona/cmd/daytona/config" +) + +var CreateCmd = &cobra.Command{ + Use: "create [REPOSITORY_URL | WORKSPACE_CONFIG_NAME]...", + Short: "Create a workspace", + GroupID: util.TARGET_GROUP, + Aliases: cmd_common.GetAliases("create"), + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.Background() + var createWorkspaceDtos []apiclient.CreateWorkspaceDTO + var existingWorkspaceTemplateNames []string + var targetId string + promptUsingTUI := len(args) == 0 + + apiClient, err := apiclient_util.GetApiClient(nil) + if err != nil { + return err + } + + c, err := config.GetConfig() + if err != nil { + return err + } + + activeProfile, err := c.GetActiveProfile() + if err != nil { + return err + } + + target, createTargetDto, err := GetTarget(ctx, GetTargetConfigParams{ + ApiClient: apiClient, + ActiveProfileName: activeProfile.Name, + TargetNameFlag: targetNameFlag, + PromptUsingTUI: promptUsingTUI, + }) + if err != nil { + if common.IsCtrlCAbort(err) { + return nil + } + return err + } + + targetName := "" + if target != nil { + targetName = target.Name + } else if createTargetDto != nil { + targetName = createTargetDto.Name + } + + existingWorkspaces, res, err := apiClient.WorkspaceAPI.ListWorkspaces(context.Background()).Execute() + if err != nil { + return apiclient_util.HandleErrorResponse(res, err) + } + + if promptUsingTUI { + err = ProcessPrompting(ctx, ProcessPromptingParams{ + ApiClient: apiClient, + CreateWorkspaceDtos: &createWorkspaceDtos, + ExistingWorkspaces: &existingWorkspaces, + WorkspaceConfigurationFlags: workspaceConfigurationFlags, + MultiWorkspaceFlag: multiWorkspaceFlag, + BlankFlag: blankFlag, + TargetName: targetName, + }) + if err != nil { + if common.IsCtrlCAbort(err) { + return nil + } else { + return err + } + } + } else { + existingWorkspaceTemplateNames, err = ProcessCmdArguments(ctx, ProcessCmdArgumentsParams{ + ApiClient: apiClient, + RepoUrls: args, + CreateWorkspaceDtos: &createWorkspaceDtos, + ExistingWorkspaces: &existingWorkspaces, + WorkspaceConfigurationFlags: workspaceConfigurationFlags, + BlankFlag: blankFlag, + }) + if err != nil { + return err + } + } + + workspaceNames := []string{} + for i := range createWorkspaceDtos { + workspaceNames = append(workspaceNames, createWorkspaceDtos[i].Name) + } + + names := append(workspaceNames, targetName) + + logs_view.SetupLongestPrefixLength(names) + + requestLogEntry := logs.LogEntry{ + Msg: views.GetPrettyLogLine("Request submitted"), + } + + if target != nil { + requestLogEntry.Label = target.Name + } else if createTargetDto != nil { + requestLogEntry.Label = createTargetDto.Name + } + + logs_view.DisplayLogEntry(requestLogEntry, logs_view.STATIC_INDEX) + + for i, workspaceTemplateName := range existingWorkspaceTemplateNames { + if workspaceTemplateName == "" { + continue + } + logs_view.DisplayLogEntry(logs.LogEntry{ + Label: createWorkspaceDtos[i].Name, + Msg: fmt.Sprintf("Using detected workspace template '%s'\n", workspaceTemplateName), + }, i) + } + + activeProfile, err = c.GetActiveProfile() + if err != nil { + return err + } + + if target != nil { + targetId = target.Id + } else if createTargetDto != nil { + targetId = createTargetDto.Id + } + + logsContext, stopLogs := context.WithCancel(context.Background()) + defer stopLogs() + + if createTargetDto != nil { + go cmd_common.ReadTargetLogs(logsContext, cmd_common.ReadLogParams{ + Id: targetId, + Label: &createTargetDto.Name, + ServerUrl: activeProfile.Api.Url, + ApiKey: activeProfile.Api.Key, + Follow: util.Pointer(true), + SkipPrefixLengthSetup: true, + }) + + t, res, err := apiClient.TargetAPI.CreateTarget(ctx).Target(*createTargetDto).Execute() + if err != nil { + return apiclient_util.HandleErrorResponse(res, err) + } + + err = cmd_common.AwaitTargetState(t.Id, apiclient.ResourceStateNameStarted) + if err != nil { + return err + } + + target = &apiclient.TargetDTO{ + Id: t.Id, + Name: t.Name, + TargetConfig: t.TargetConfig, + TargetConfigId: t.TargetConfigId, + Default: t.Default, + } + } + + var tsConn *tsnet.Server + if !common.IsLocalDockerTarget(target.TargetConfig.ProviderInfo.Name, target.TargetConfig.Options, target.TargetConfig.ProviderInfo.RunnerId) || activeProfile.Id != "default" { + tsConn, err = tailscale.GetConnection(&activeProfile) + if err != nil { + return err + } + } + + for i := range createWorkspaceDtos { + createWorkspaceDtos[i].TargetId = targetId + go cmd_common.ReadWorkspaceLogs(logsContext, cmd_common.ReadLogParams{ + Id: createWorkspaceDtos[i].Id, + Label: &createWorkspaceDtos[i].Name, + ServerUrl: activeProfile.Api.Url, + ApiKey: activeProfile.Api.Key, + Index: util.Pointer(i), + Follow: util.Pointer(true), + SkipPrefixLengthSetup: true, + }) + + _, res, err := apiClient.WorkspaceAPI.CreateWorkspace(ctx).Workspace(createWorkspaceDtos[i]).Execute() + if err != nil { + return apiclient_util.HandleErrorResponse(res, err) + } + + err = cmd_common.AwaitWorkspaceState(createWorkspaceDtos[i].Id, apiclient.ResourceStateNameStarted) + if err != nil { + return err + } + } + + gpgKey, err := cmd_common.GetGitProviderGpgKey(apiClient, ctx, createWorkspaceDtos[0].GitProviderConfigId) + if err != nil { + log.Warn(err) + } + + err = waitForDial(target, createWorkspaceDtos[0].Id, &activeProfile, tsConn, gpgKey) + if err != nil { + return err + } + + stopLogs() + + // Make sure terminal cursor is reset + fmt.Print("\033[?25h") + + chosenIdeId := c.DefaultIdeId + if IdeFlag != "" { + chosenIdeId = IdeFlag + } + + ideList := config.GetIdeList() + var chosenIde config.Ide + + for _, ide := range ideList { + if ide.Id == chosenIdeId { + chosenIde = ide + } + } + + fmt.Println() + + createdWorkspaces := []apiclient.WorkspaceDTO{} + for _, createWorkspaceDto := range createWorkspaceDtos { + ws, _, err := apiclient_util.GetWorkspace(createWorkspaceDto.Id) + if err != nil { + return err + } + createdWorkspaces = append(createdWorkspaces, *ws) + } + + if len(createdWorkspaces) > 1 { + info.RenderMulti(createdWorkspaces, chosenIde.Name, false) + } else { + info.Render(&createdWorkspaces[0], chosenIde.Name, false) + } + + if noIdeFlag { + views.RenderCreationInfoMessage("Run 'daytona code' when you're ready to start developing") + return nil + } + + views.RenderCreationInfoMessage(fmt.Sprintf("Opening the workspace in %s ...", chosenIde.Name)) + + return cmd_common.OpenIDE(chosenIdeId, activeProfile, createWorkspaceDtos[0].Name, *createdWorkspaces[0].ProviderMetadata, YesFlag, gpgKey) + }, +} + +var YesFlag bool +var targetNameFlag string +var IdeFlag string +var noIdeFlag bool +var blankFlag bool +var multiWorkspaceFlag bool + +var workspaceConfigurationFlags = cmd_common.WorkspaceConfigurationFlags{ + Builder: new(views_util.BuildChoice), + CustomImage: new(string), + CustomImageUser: new(string), + Branches: new([]string), + DevcontainerPath: new(string), + EnvVars: new([]string), + Manual: new(bool), + GitProviderConfig: new(string), + Labels: new([]string), +} + +func init() { + ideList := config.GetIdeList() + ids := make([]string, len(ideList)) + for i, ide := range ideList { + ids[i] = ide.Id + } + ideListStr := strings.Join(ids, ", ") + + CreateCmd.Flags().StringVarP(&IdeFlag, "ide", "i", "", fmt.Sprintf("Specify the IDE (%s)", ideListStr)) + CreateCmd.Flags().StringVarP(&targetNameFlag, "target", "t", "", "Specify the target (e.g. 'local')") + CreateCmd.Flags().BoolVar(&blankFlag, "blank", false, "Create a blank workspace without using existing templates") + CreateCmd.Flags().BoolVarP(&noIdeFlag, "no-ide", "n", false, "Do not open the target in the IDE after target creation") + CreateCmd.Flags().BoolVar(&multiWorkspaceFlag, "multi-workspace", false, "Target with multiple workspaces/repos") + CreateCmd.Flags().BoolVarP(&YesFlag, "yes", "y", false, "Automatically confirm any prompts") + CreateCmd.Flags().StringSliceVar(workspaceConfigurationFlags.Branches, "branch", []string{}, "Specify the Git branches to use in the workspaces") + + cmd_common.AddWorkspaceConfigurationFlags(CreateCmd, workspaceConfigurationFlags, true) +} + +func waitForDial(target *apiclient.TargetDTO, workspaceId string, activeProfile *config.Profile, tsConn *tsnet.Server, gpgKey *string) error { + if common.IsLocalDockerTarget(target.TargetConfig.ProviderInfo.Name, target.TargetConfig.Options, target.TargetConfig.ProviderInfo.RunnerId) && (activeProfile != nil && activeProfile.Id == "default") { + err := config.EnsureSshConfigEntryAdded(activeProfile.Id, workspaceId, gpgKey) + if err != nil { + return err + } + + workspaceHostname := config.GetHostname(activeProfile.Id, workspaceId) + + for { + sshCommand := exec.Command("ssh", workspaceHostname, "daytona", "version") + sshCommand.Stdin = nil + sshCommand.Stdout = nil + sshCommand.Stderr = &util.TraceLogWriter{} + + err = sshCommand.Run() + if err == nil { + return nil + } + + time.Sleep(100 * time.Millisecond) + } + } + + connectChan := make(chan error) + spinner := time.After(15 * time.Second) + timeout := time.After(2 * time.Minute) + + go func() { + for { + dialConn, err := tsConn.Dial(context.Background(), "tcp", fmt.Sprintf("%s:%d", common.GetTailscaleHostname(workspaceId), ssh_config.SSH_PORT)) + if err == nil { + connectChan <- dialConn.Close() + return + } + time.Sleep(100 * time.Millisecond) + } + }() + + select { + case err := <-connectChan: + return err + case <-spinner: + err := views_util.WithInlineSpinner("Connection to tailscale is taking longer than usual", func() error { + select { + case err := <-connectChan: + return err + case <-timeout: + return errors.New("secure connection to the Daytona Server could not be established. Please check your internet connection or Tailscale availability") + } + }) + return err + } +} diff --git a/pkg/cmd/workspace/create/creation_data.go b/pkg/cmd/workspace/create/creation_data.go new file mode 100644 index 0000000000..5c8e1ecc2f --- /dev/null +++ b/pkg/cmd/workspace/create/creation_data.go @@ -0,0 +1,396 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package create + +import ( + "context" + "fmt" + "net/http" + "net/url" + "path/filepath" + "regexp" + "slices" + "strconv" + "strings" + + apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" + "github.com/daytonaio/daytona/pkg/apiclient" + cmd_common "github.com/daytonaio/daytona/pkg/cmd/common" + "github.com/daytonaio/daytona/pkg/common" + "github.com/daytonaio/daytona/pkg/views/selection" + views_util "github.com/daytonaio/daytona/pkg/views/util" + "github.com/daytonaio/daytona/pkg/views/workspace/create" + "github.com/docker/docker/pkg/stringid" +) + +type WorkspacesDataPromptParams struct { + UserGitProviders []apiclient.GitProvider + WorkspaceTemplates []apiclient.WorkspaceTemplate + Manual bool + SkipBranchSelection bool + MultiWorkspace bool + BlankWorkspace bool + ApiClient *apiclient.APIClient + Defaults *views_util.WorkspaceTemplateDefaults +} + +func GetWorkspacesCreationDataFromPrompt(ctx context.Context, params WorkspacesDataPromptParams) ([]apiclient.CreateWorkspaceDTO, error) { + var workspaceList []apiclient.CreateWorkspaceDTO + // keep track of visited repos, will help in keeping workspace names unique + // since these are later saved into the db under a unique constraint field. + selectedRepos := make(map[string]int) + + for i := 1; params.MultiWorkspace || i == 1; i++ { + var err error + + if i > 2 { + addMore, err := create.RunAddMoreWorkspacesForm() + if err != nil { + return nil, err + } + if !addMore { + break + } + } + + if len(params.WorkspaceTemplates) > 0 && !params.BlankWorkspace { + workspaceTemplate := selection.GetWorkspaceTemplateFromPrompt(params.WorkspaceTemplates, i, true, false, "Use") + if workspaceTemplate == nil { + return nil, common.ErrCtrlCAbort + } + + workspaceNames := []string{} + for _, w := range workspaceList { + workspaceNames = append(workspaceNames, w.Name) + } + + // Append occurence number to keep duplicate entries unique + repoUrl := workspaceTemplate.RepositoryUrl + if len(selectedRepos) > 0 && selectedRepos[repoUrl] > 1 { + workspaceTemplate.Name += strconv.Itoa(selectedRepos[repoUrl]) + } + + if workspaceTemplate.Name != selection.BlankWorkspaceIdentifier { + workspaceName := GetSuggestedName(workspaceTemplate.Name, workspaceNames) + + getRepoContext := apiclient.GetRepositoryContext{ + Url: workspaceTemplate.RepositoryUrl, + } + + branch, err := GetBranchFromWorkspaceTemplate(ctx, workspaceTemplate, params.ApiClient, i) + if err != nil { + return nil, err + } + + if branch != nil { + getRepoContext.Branch = &branch.Name + getRepoContext.Sha = &branch.Sha + } + + templateRepo, res, err := params.ApiClient.GitProviderAPI.GetGitContext(ctx).Repository(getRepoContext).Execute() + if err != nil { + return nil, apiclient_util.HandleErrorResponse(res, err) + } + + createWorkspaceDto := apiclient.CreateWorkspaceDTO{ + Name: workspaceName, + GitProviderConfigId: workspaceTemplate.GitProviderConfigId, + Source: apiclient.CreateWorkspaceSourceDTO{ + Repository: *templateRepo, + }, + BuildConfig: workspaceTemplate.BuildConfig, + Image: params.Defaults.Image, + User: params.Defaults.ImageUser, + EnvVars: workspaceTemplate.EnvVars, + Labels: workspaceTemplate.Labels, + } + + if workspaceTemplate.Image != "" { + createWorkspaceDto.Image = &workspaceTemplate.Image + } + + if workspaceTemplate.User != "" { + createWorkspaceDto.User = &workspaceTemplate.User + } + + if workspaceTemplate.GitProviderConfigId == nil || *workspaceTemplate.GitProviderConfigId == "" { + gitProviderConfigId, res, err := params.ApiClient.GitProviderAPI.FindGitProviderIdForUrl(ctx, url.QueryEscape(workspaceTemplate.RepositoryUrl)).Execute() + if err != nil { + return nil, apiclient_util.HandleErrorResponse(res, err) + } + createWorkspaceDto.GitProviderConfigId = &gitProviderConfigId + } + + workspaceList = append(workspaceList, createWorkspaceDto) + continue + } + } + + providerRepo, gitProviderConfigId, err := getRepositoryFromWizard(ctx, RepositoryWizardParams{ + ApiClient: params.ApiClient, + UserGitProviders: params.UserGitProviders, + Manual: params.Manual, + MultiWorkspace: params.MultiWorkspace, + SkipBranchSelection: params.SkipBranchSelection, + WorkspaceOrder: i, + SelectedRepos: selectedRepos, + }) + if err != nil { + return nil, err + } + + if gitProviderConfigId == selection.CustomRepoIdentifier || gitProviderConfigId == selection.CREATE_FROM_SAMPLE { + gitProviderConfigs, res, err := params.ApiClient.GitProviderAPI.ListGitProvidersForUrl(ctx, url.QueryEscape(providerRepo.Url)).Execute() + if err != nil { + return nil, apiclient_util.HandleErrorResponse(res, err) + } + + if len(gitProviderConfigs) == 1 { + gitProviderConfigId = gitProviderConfigs[0].Id + } else if len(gitProviderConfigs) > 1 { + gp := selection.GetGitProviderConfigFromPrompt(selection.GetGitProviderConfigParams{ + GitProviderConfigs: gitProviderConfigs, + ActionVerb: "Use", + }) + if gp == nil { + return nil, common.ErrCtrlCAbort + } + gitProviderConfigId = gp.Id + } else { + gitProviderConfigId = "" + } + } + + getRepoContext := createGetRepoContextFromRepository(providerRepo) + + var res *http.Response + providerRepo, res, err = params.ApiClient.GitProviderAPI.GetGitContext(ctx).Repository(getRepoContext).Execute() + if err != nil { + return nil, apiclient_util.HandleErrorResponse(res, err) + } + + providerRepoName, err := GetSanitizedWorkspaceName(providerRepo.Name) + if err != nil { + return nil, err + } + + workspaceList = append(workspaceList, newCreateWorkspaceTemplateDTO(params, providerRepo, providerRepoName, gitProviderConfigId)) + } + + return workspaceList, nil +} + +func GetWorkspaceNameFromRepo(repoUrl string) string { + workspaceNameSlugRegex := regexp.MustCompile(`[^a-zA-Z0-9-]`) + return workspaceNameSlugRegex.ReplaceAllString(strings.TrimSuffix(strings.ToLower(filepath.Base(repoUrl)), ".git"), "-") +} + +func GetSuggestedName(initialSuggestion string, existingNames []string) string { + suggestion := initialSuggestion + + if !slices.Contains(existingNames, suggestion) { + return suggestion + } else { + i := 2 + for { + newSuggestion := fmt.Sprintf("%s%d", suggestion, i) + if !slices.Contains(existingNames, newSuggestion) { + return newSuggestion + } + i++ + } + } +} + +func GetSanitizedWorkspaceName(workspaceName string) (string, error) { + workspaceName, err := url.QueryUnescape(workspaceName) + if err != nil { + return "", err + } + workspaceName = strings.ReplaceAll(workspaceName, " ", "-") + + return workspaceName, nil +} + +func GetBranchFromWorkspaceTemplate(ctx context.Context, workspaceTemplate *apiclient.WorkspaceTemplate, apiClient *apiclient.APIClient, workspaceOrder int) (*apiclient.GitBranch, error) { + encodedURLParam := url.QueryEscape(workspaceTemplate.RepositoryUrl) + + repoResponse, res, err := apiClient.GitProviderAPI.GetGitContext(ctx).Repository(apiclient.GetRepositoryContext{ + Url: workspaceTemplate.RepositoryUrl, + }).Execute() + if err != nil { + return nil, apiclient_util.HandleErrorResponse(res, err) + } + + gitProviderConfigId, res, err := apiClient.GitProviderAPI.FindGitProviderIdForUrl(ctx, encodedURLParam).Execute() + if err != nil { + return nil, apiclient_util.HandleErrorResponse(res, err) + } + + gitProvider, _, err := apiClient.GitProviderAPI.FindGitProvider(ctx, gitProviderConfigId).Execute() + if err == nil && gitProvider != nil { + gitProviderConfigId = gitProvider.ProviderId + } + + branchWizardConfig := BranchWizardParams{ + ApiClient: apiClient, + GitProviderConfigId: gitProviderConfigId, + NamespaceId: repoResponse.Owner, + ChosenRepo: repoResponse, + WorkspaceOrder: workspaceOrder, + } + + repo, err := SetBranchFromWizard(branchWizardConfig) + if err != nil { + return nil, err + } + + if repo == nil { + return nil, common.ErrCtrlCAbort + } + + return &apiclient.GitBranch{ + Name: repo.Branch, + Sha: repo.Sha, + }, nil +} + +func GetCreateWorkspaceDtoFromFlags(workspaceConfigurationFlags cmd_common.WorkspaceConfigurationFlags) (*apiclient.CreateWorkspaceDTO, error) { + workspace := &apiclient.CreateWorkspaceDTO{ + GitProviderConfigId: workspaceConfigurationFlags.GitProviderConfig, + BuildConfig: &apiclient.BuildConfig{}, + } + + if *workspaceConfigurationFlags.Builder == views_util.DEVCONTAINER || *workspaceConfigurationFlags.DevcontainerPath != "" { + devcontainerFilePath := create.DEVCONTAINER_FILEPATH + if *workspaceConfigurationFlags.DevcontainerPath != "" { + devcontainerFilePath = *workspaceConfigurationFlags.DevcontainerPath + } + workspace.BuildConfig.Devcontainer = &apiclient.DevcontainerConfig{ + FilePath: devcontainerFilePath, + } + + } + + if *workspaceConfigurationFlags.Builder == views_util.NONE || *workspaceConfigurationFlags.CustomImage != "" || *workspaceConfigurationFlags.CustomImageUser != "" { + workspace.BuildConfig = nil + if *workspaceConfigurationFlags.CustomImage != "" || *workspaceConfigurationFlags.CustomImageUser != "" { + workspace.Image = workspaceConfigurationFlags.CustomImage + workspace.User = workspaceConfigurationFlags.CustomImageUser + } + } + + envVars := make(map[string]string) + + if workspaceConfigurationFlags.EnvVars != nil { + var err error + envVars, err = cmd_common.MapKeyValue(*workspaceConfigurationFlags.EnvVars) + if err != nil { + return nil, err + } + } + + labels := make(map[string]string) + + if workspaceConfigurationFlags.Labels != nil { + var err error + labels, err = cmd_common.MapKeyValue(*workspaceConfigurationFlags.Labels) + if err != nil { + return nil, err + } + } + + workspace.EnvVars = envVars + workspace.Labels = labels + + return workspace, nil +} + +func GetGitProviderConfigIdFromFlag(ctx context.Context, apiClient *apiclient.APIClient, gitProviderConfigFlag *string) (*string, error) { + if gitProviderConfigFlag == nil || *gitProviderConfigFlag == "" { + return gitProviderConfigFlag, nil + } + + gitProviderConfigs, res, err := apiClient.GitProviderAPI.ListGitProviders(ctx).Execute() + if err != nil { + return nil, apiclient_util.HandleErrorResponse(res, err) + } + + for _, gitProviderConfig := range gitProviderConfigs { + if gitProviderConfig.Id == *gitProviderConfigFlag { + return &gitProviderConfig.Id, nil + } + if gitProviderConfig.Alias == *gitProviderConfigFlag { + return &gitProviderConfig.Id, nil + } + } + + return nil, fmt.Errorf("git provider config '%s' not found", *gitProviderConfigFlag) +} + +func newCreateWorkspaceTemplateDTO(params WorkspacesDataPromptParams, providerRepo *apiclient.GitRepository, providerRepoName string, gitProviderConfigId string) apiclient.CreateWorkspaceDTO { + workspace := apiclient.CreateWorkspaceDTO{ + Name: providerRepoName, + GitProviderConfigId: &gitProviderConfigId, + Source: apiclient.CreateWorkspaceSourceDTO{ + Repository: *providerRepo, + }, + BuildConfig: &apiclient.BuildConfig{}, + Image: params.Defaults.Image, + User: params.Defaults.ImageUser, + EnvVars: map[string]string{}, + Labels: map[string]string{}, + } + + return workspace +} + +func createGetRepoContextFromRepository(providerRepo *apiclient.GitRepository) apiclient.GetRepositoryContext { + result := apiclient.GetRepositoryContext{ + Id: &providerRepo.Id, + Name: &providerRepo.Name, + Owner: &providerRepo.Owner, + Sha: &providerRepo.Sha, + Source: &providerRepo.Source, + Url: providerRepo.Url, + Branch: &providerRepo.Branch, + } + + if providerRepo.Path != nil { + result.Path = providerRepo.Path + } + + return result +} + +func setInitialWorkspaceNames(createWorkspaceDtos *[]apiclient.CreateWorkspaceDTO, existingWorkspaces []apiclient.WorkspaceDTO) { + existingNames := make(map[string]bool) + for _, workspace := range existingWorkspaces { + existingNames[workspace.Name] = true + } + + for i := range *createWorkspaceDtos { + originalName := (*createWorkspaceDtos)[i].Name + newName := originalName + counter := 2 + + for existingNames[newName] { + newName = fmt.Sprintf("%s%d", originalName, counter) + counter++ + } + + (*createWorkspaceDtos)[i].Name = newName + existingNames[newName] = true + } +} + +func generateWorkspaceIds(createWorkspaceDtos *[]apiclient.CreateWorkspaceDTO) []string { + for i := range *createWorkspaceDtos { + wsId := stringid.GenerateRandomID() + wsId = stringid.TruncateID(wsId) + (*createWorkspaceDtos)[i].Id = wsId + } + + return nil +} diff --git a/pkg/cmd/workspace/create/get_target.go b/pkg/cmd/workspace/create/get_target.go new file mode 100644 index 0000000000..c1cb367e2c --- /dev/null +++ b/pkg/cmd/workspace/create/get_target.go @@ -0,0 +1,76 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package create + +import ( + "context" + "fmt" + + apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" + "github.com/daytonaio/daytona/pkg/apiclient" + "github.com/daytonaio/daytona/pkg/cmd/target" + "github.com/daytonaio/daytona/pkg/common" + "github.com/daytonaio/daytona/pkg/views/target/selection" +) + +type GetTargetConfigParams struct { + ApiClient *apiclient.APIClient + ActiveProfileName string + TargetNameFlag string + PromptUsingTUI bool +} + +func GetTarget(ctx context.Context, params GetTargetConfigParams) (t *apiclient.TargetDTO, createTargetDto *apiclient.CreateTargetDTO, err error) { + targetList, res, err := params.ApiClient.TargetAPI.ListTargets(ctx).Execute() + if err != nil { + return nil, nil, apiclient_util.HandleErrorResponse(res, err) + } + + if params.TargetNameFlag != "" { + for _, t := range targetList { + if t.Name == params.TargetNameFlag { + return &t, nil, nil + } + } + return nil, nil, fmt.Errorf("target '%s' not found", params.TargetNameFlag) + } + + if !params.PromptUsingTUI { + for _, t := range targetList { + if t.Default { + return &t, nil, nil + } + } + } + + if len(targetList) == 0 { + createTargetDto, err := target.CreateTargetDtoFlow(ctx, target.TargetCreationParams{ + ApiClient: params.ApiClient, + ActiveProfileName: params.ActiveProfileName, + }) + if err != nil { + return nil, nil, err + } + return nil, createTargetDto, nil + } + + selectedTarget := selection.GetTargetFromPrompt(targetList, true, "Use") + + if selectedTarget == nil { + return nil, nil, common.ErrCtrlCAbort + } + + if selectedTarget.Name == selection.NewTargetIdentifier { + createTargetDto, err := target.CreateTargetDtoFlow(ctx, target.TargetCreationParams{ + ApiClient: params.ApiClient, + ActiveProfileName: params.ActiveProfileName, + }) + if err != nil { + return nil, createTargetDto, err + } + return nil, createTargetDto, nil + } + + return selectedTarget, nil, nil +} diff --git a/pkg/cmd/workspace/create/process_cmd_arguments.go b/pkg/cmd/workspace/create/process_cmd_arguments.go new file mode 100644 index 0000000000..1c04e141c3 --- /dev/null +++ b/pkg/cmd/workspace/create/process_cmd_arguments.go @@ -0,0 +1,184 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package create + +import ( + "context" + "fmt" + "net/http" + "net/url" + + "github.com/daytonaio/daytona/internal/util" + apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" + "github.com/daytonaio/daytona/pkg/apiclient" + cmd_common "github.com/daytonaio/daytona/pkg/cmd/common" + "github.com/daytonaio/daytona/pkg/common" + "github.com/daytonaio/daytona/pkg/views/selection" + views_util "github.com/daytonaio/daytona/pkg/views/util" +) + +type ProcessCmdArgumentsParams struct { + ApiClient *apiclient.APIClient + RepoUrls []string + CreateWorkspaceDtos *[]apiclient.CreateWorkspaceDTO + ExistingWorkspaces *[]apiclient.WorkspaceDTO + WorkspaceConfigurationFlags cmd_common.WorkspaceConfigurationFlags + BlankFlag bool +} + +type ProcessGitUrlParams struct { + ApiClient *apiclient.APIClient + RepoUrl string + CreateWorkspaceDtos *[]apiclient.CreateWorkspaceDTO + WorkspaceConfigurationFlags cmd_common.WorkspaceConfigurationFlags + Branch *string + BlankFlag bool +} + +func ProcessCmdArguments(ctx context.Context, params ProcessCmdArgumentsParams) ([]string, error) { + if len(params.RepoUrls) == 0 { + return nil, fmt.Errorf("no repository URLs provided") + } + + if len(params.RepoUrls) > 1 && cmd_common.CheckAnyWorkspaceConfigurationFlagSet(params.WorkspaceConfigurationFlags) { + return nil, fmt.Errorf("can't set custom workspace configuration properties for multiple workspaces") + } + + if *params.WorkspaceConfigurationFlags.Builder != "" && *params.WorkspaceConfigurationFlags.Builder != views_util.DEVCONTAINER && *params.WorkspaceConfigurationFlags.DevcontainerPath != "" { + return nil, fmt.Errorf("can't set devcontainer file path if builder is not set to %s", views_util.DEVCONTAINER) + } + + var workspaceTemplate *apiclient.WorkspaceTemplate + + existingWorkspaceTemplateNames := []string{} + + for i, repoUrl := range params.RepoUrls { + var branch *string + if len(*params.WorkspaceConfigurationFlags.Branches) > i { + branch = &(*params.WorkspaceConfigurationFlags.Branches)[i] + } + + validatedUrl, err := util.GetValidatedUrl(repoUrl) + if err == nil { + // The argument is a Git URL + existingWorkspaceTemplateName, err := processGitURL(ctx, ProcessGitUrlParams{ + ApiClient: params.ApiClient, + RepoUrl: validatedUrl, + CreateWorkspaceDtos: params.CreateWorkspaceDtos, + WorkspaceConfigurationFlags: params.WorkspaceConfigurationFlags, + Branch: branch, + BlankFlag: params.BlankFlag, + }) + if err != nil { + return nil, err + } + if existingWorkspaceTemplateName != nil { + existingWorkspaceTemplateNames = append(existingWorkspaceTemplateNames, *existingWorkspaceTemplateName) + } else { + existingWorkspaceTemplateNames = append(existingWorkspaceTemplateNames, "") + } + + continue + } + + // The argument is not a Git URL - try getting the workspace template + workspaceTemplate, _, err = params.ApiClient.WorkspaceTemplateAPI.FindWorkspaceTemplate(ctx, repoUrl).Execute() + if err != nil { + return nil, fmt.Errorf("failed to parse the URL or fetch the workspace template for '%s'", repoUrl) + } + + existingWorkspaceTemplateName, err := AddWorkspaceFromTemplate(ctx, AddWorkspaceFromTemplateParams{ + WorkspaceTemplate: workspaceTemplate, + ApiClient: params.ApiClient, + Workspaces: params.CreateWorkspaceDtos, + BranchFlag: branch, + }) + if err != nil { + return nil, err + } + if existingWorkspaceTemplateName != nil { + existingWorkspaceTemplateNames = append(existingWorkspaceTemplateNames, *existingWorkspaceTemplateName) + } else { + existingWorkspaceTemplateNames = append(existingWorkspaceTemplateNames, "") + } + } + + generateWorkspaceIds(params.CreateWorkspaceDtos) + setInitialWorkspaceNames(params.CreateWorkspaceDtos, *params.ExistingWorkspaces) + + return existingWorkspaceTemplateNames, nil +} + +func processGitURL(ctx context.Context, params ProcessGitUrlParams) (*string, error) { + encodedURLParam := url.QueryEscape(params.RepoUrl) + + if !params.BlankFlag { + workspaceTemplate, res, err := params.ApiClient.WorkspaceTemplateAPI.GetDefaultWorkspaceTemplate(ctx, encodedURLParam).Execute() + if err == nil { + workspaceTemplate.GitProviderConfigId = params.WorkspaceConfigurationFlags.GitProviderConfig + return AddWorkspaceFromTemplate(ctx, AddWorkspaceFromTemplateParams{ + WorkspaceTemplate: workspaceTemplate, + ApiClient: params.ApiClient, + Workspaces: params.CreateWorkspaceDtos, + BranchFlag: params.Branch, + }) + } + + if res.StatusCode != http.StatusNotFound { + return nil, apiclient_util.HandleErrorResponse(res, err) + } + } + + repo, res, err := params.ApiClient.GitProviderAPI.GetGitContext(ctx).Repository(apiclient.GetRepositoryContext{ + Url: params.RepoUrl, + Branch: params.Branch, + }).Execute() + if err != nil { + return nil, apiclient_util.HandleErrorResponse(res, err) + } + + workspaceName, err := GetSanitizedWorkspaceName(repo.Name) + if err != nil { + return nil, err + } + + params.WorkspaceConfigurationFlags.GitProviderConfig, err = GetGitProviderConfigIdFromFlag(ctx, params.ApiClient, params.WorkspaceConfigurationFlags.GitProviderConfig) + if err != nil { + return nil, err + } + + if params.WorkspaceConfigurationFlags.GitProviderConfig == nil || *params.WorkspaceConfigurationFlags.GitProviderConfig == "" { + gitProviderConfigs, res, err := params.ApiClient.GitProviderAPI.ListGitProvidersForUrl(ctx, url.QueryEscape(params.RepoUrl)).Execute() + if err != nil { + return nil, apiclient_util.HandleErrorResponse(res, err) + } + + if len(gitProviderConfigs) == 1 { + params.WorkspaceConfigurationFlags.GitProviderConfig = &gitProviderConfigs[0].Id + } else if len(gitProviderConfigs) > 1 { + gp := selection.GetGitProviderConfigFromPrompt(selection.GetGitProviderConfigParams{ + GitProviderConfigs: gitProviderConfigs, + ActionVerb: "Use", + }) + if gp == nil { + return nil, common.ErrCtrlCAbort + } + params.WorkspaceConfigurationFlags.GitProviderConfig = &gp.Id + } + } + + workspace, err := GetCreateWorkspaceDtoFromFlags(params.WorkspaceConfigurationFlags) + if err != nil { + return nil, err + } + + workspace.Name = workspaceName + workspace.Source = apiclient.CreateWorkspaceSourceDTO{ + Repository: *repo, + } + + *params.CreateWorkspaceDtos = append(*params.CreateWorkspaceDtos, *workspace) + + return nil, nil +} diff --git a/pkg/cmd/workspace/create/process_prompting.go b/pkg/cmd/workspace/create/process_prompting.go new file mode 100644 index 0000000000..924fc74fbd --- /dev/null +++ b/pkg/cmd/workspace/create/process_prompting.go @@ -0,0 +1,90 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package create + +import ( + "context" + "errors" + + "github.com/daytonaio/daytona/internal/util" + apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" + "github.com/daytonaio/daytona/pkg/apiclient" + cmd_common "github.com/daytonaio/daytona/pkg/cmd/common" + views_util "github.com/daytonaio/daytona/pkg/views/util" + "github.com/daytonaio/daytona/pkg/views/workspace/create" +) + +type ProcessPromptingParams struct { + ApiClient *apiclient.APIClient + CreateWorkspaceDtos *[]apiclient.CreateWorkspaceDTO + ExistingWorkspaces *[]apiclient.WorkspaceDTO + WorkspaceConfigurationFlags cmd_common.WorkspaceConfigurationFlags + MultiWorkspaceFlag bool + BlankFlag bool + TargetName string + IsImporting *bool +} + +func ProcessPrompting(ctx context.Context, params ProcessPromptingParams) error { + if cmd_common.CheckAnyWorkspaceConfigurationFlagSet(params.WorkspaceConfigurationFlags) || (params.WorkspaceConfigurationFlags.Branches != nil && len(*params.WorkspaceConfigurationFlags.Branches) > 0) { + return errors.New("please provide the repository URL in order to set up custom workspace details through the CLI") + } + + gitProviders, res, err := params.ApiClient.GitProviderAPI.ListGitProviders(ctx).Execute() + if err != nil { + return apiclient_util.HandleErrorResponse(res, err) + } + + workspaceTemplates, res, err := params.ApiClient.WorkspaceTemplateAPI.ListWorkspaceTemplates(ctx).Execute() + if err != nil { + return apiclient_util.HandleErrorResponse(res, err) + } + + apiServerConfig, res, err := params.ApiClient.ServerAPI.GetConfig(ctx).Execute() + if err != nil { + return apiclient_util.HandleErrorResponse(res, err) + } + + workspaceDefaults := &views_util.WorkspaceTemplateDefaults{ + BuildChoice: views_util.AUTOMATIC, + Image: &apiServerConfig.DefaultWorkspaceImage, + ImageUser: &apiServerConfig.DefaultWorkspaceUser, + DevcontainerFilePath: create.DEVCONTAINER_FILEPATH, + Labels: make(map[string]string), + } + + *params.CreateWorkspaceDtos, err = GetWorkspacesCreationDataFromPrompt(ctx, WorkspacesDataPromptParams{ + UserGitProviders: gitProviders, + WorkspaceTemplates: workspaceTemplates, + Manual: *params.WorkspaceConfigurationFlags.Manual, + MultiWorkspace: params.MultiWorkspaceFlag, + BlankWorkspace: params.BlankFlag, + ApiClient: params.ApiClient, + Defaults: workspaceDefaults, + }) + + if err != nil { + return err + } + + generateWorkspaceIds(params.CreateWorkspaceDtos) + setInitialWorkspaceNames(params.CreateWorkspaceDtos, *params.ExistingWorkspaces) + + submissionFormConfig := create.SubmissionFormParams{ + ChosenName: ¶ms.TargetName, + WorkspaceList: params.CreateWorkspaceDtos, + NameLabel: params.TargetName, + Defaults: workspaceDefaults, + ExistingWorkspaceNames: util.ArrayMap(*params.ExistingWorkspaces, func(w apiclient.WorkspaceDTO) string { + return w.Name + }), + } + + err = create.RunSubmissionForm(submissionFormConfig) + if err != nil { + return err + } + + return nil +} diff --git a/pkg/cmd/workspace/util/repository_wizard.go b/pkg/cmd/workspace/create/repository_wizard.go similarity index 83% rename from pkg/cmd/workspace/util/repository_wizard.go rename to pkg/cmd/workspace/create/repository_wizard.go index d957a88b68..de66fa7809 100644 --- a/pkg/cmd/workspace/util/repository_wizard.go +++ b/pkg/cmd/workspace/create/repository_wizard.go @@ -1,7 +1,7 @@ // Copyright 2024 Daytona Platforms Inc. // SPDX-License-Identifier: Apache-2.0 -package util +package create import ( "context" @@ -13,9 +13,9 @@ import ( "github.com/daytonaio/daytona/pkg/common" "github.com/daytonaio/daytona/pkg/views" gitprovider_view "github.com/daytonaio/daytona/pkg/views/gitprovider" + "github.com/daytonaio/daytona/pkg/views/selection" views_util "github.com/daytonaio/daytona/pkg/views/util" "github.com/daytonaio/daytona/pkg/views/workspace/create" - "github.com/daytonaio/daytona/pkg/views/workspace/selection" log "github.com/sirupsen/logrus" ) @@ -38,37 +38,35 @@ func gitProviderAppendsPersonalNamespace(providerId string) bool { } } -type RepositoryWizardConfig struct { +type RepositoryWizardParams struct { ApiClient *apiclient.APIClient UserGitProviders []apiclient.GitProvider Manual bool - MultiProject bool + MultiWorkspace bool SkipBranchSelection bool - ProjectOrder int + WorkspaceOrder int SelectedRepos map[string]int } -func getRepositoryFromWizard(config RepositoryWizardConfig) (*apiclient.GitRepository, string, error) { +func getRepositoryFromWizard(ctx context.Context, params RepositoryWizardParams) (*apiclient.GitRepository, string, error) { var gitProviderConfigId string var namespaceId string var err error - ctx := context.Background() - - samples, res, err := config.ApiClient.SampleAPI.ListSamples(ctx).Execute() + samples, res, err := params.ApiClient.SampleAPI.ListSamples(ctx).Execute() if err != nil { log.Debug("Error fetching samples: ", apiclient_util.HandleErrorResponse(res, err)) } - if (len(config.UserGitProviders) == 0 && len(samples) == 0) || config.Manual { - repo, err := create.GetRepositoryFromUrlInput(config.MultiProject, config.ProjectOrder, config.ApiClient, config.SelectedRepos) + if (len(params.UserGitProviders) == 0 && len(samples) == 0) || params.Manual { + repo, err := create.GetRepositoryFromUrlInput(params.MultiWorkspace, params.WorkspaceOrder, params.ApiClient, params.SelectedRepos) return repo, selection.CustomRepoIdentifier, err } supportedProviders := config_const.GetSupportedGitProviders() var gitProviderViewList []gitprovider_view.GitProviderView - for _, gitProvider := range config.UserGitProviders { + for _, gitProvider := range params.UserGitProviders { for _, supportedProvider := range supportedProviders { if gitProvider.ProviderId == supportedProvider.Id { gitProviderViewList = append(gitProviderViewList, @@ -84,13 +82,13 @@ func getRepositoryFromWizard(config RepositoryWizardConfig) (*apiclient.GitRepos } } - gitProviderConfigId = selection.GetProviderIdFromPrompt(gitProviderViewList, config.ProjectOrder, len(samples) > 0) + gitProviderConfigId = selection.GetProviderIdFromPrompt(gitProviderViewList, params.WorkspaceOrder, len(samples) > 0) if gitProviderConfigId == "" { return nil, "", common.ErrCtrlCAbort } if gitProviderConfigId == selection.CustomRepoIdentifier { - repo, err := create.GetRepositoryFromUrlInput(config.MultiProject, config.ProjectOrder, config.ApiClient, config.SelectedRepos) + repo, err := create.GetRepositoryFromUrlInput(params.MultiWorkspace, params.WorkspaceOrder, params.ApiClient, params.SelectedRepos) return repo, selection.CustomRepoIdentifier, err } @@ -100,7 +98,7 @@ func getRepositoryFromWizard(config RepositoryWizardConfig) (*apiclient.GitRepos return nil, "", common.ErrCtrlCAbort } - repo, res, err := config.ApiClient.GitProviderAPI.GetGitContext(ctx).Repository(apiclient.GetRepositoryContext{ + repo, res, err := params.ApiClient.GitProviderAPI.GetGitContext(ctx).Repository(apiclient.GetRepositoryContext{ Url: sample.GitUrl, }).Execute() if err != nil { @@ -130,7 +128,7 @@ func getRepositoryFromWizard(config RepositoryWizardConfig) (*apiclient.GitRepos for { err = views_util.WithSpinner("Loading Namespaces", func() error { - namespaces, _, err := config.ApiClient.GitProviderAPI.GetNamespaces(ctx, gitProviderConfigId).Page(page).PerPage(perPage).Execute() + namespaces, _, err := params.ApiClient.GitProviderAPI.GetNamespaces(ctx, gitProviderConfigId).Page(page).PerPage(perPage).Execute() if err != nil { return err } @@ -169,7 +167,7 @@ func getRepositoryFromWizard(config RepositoryWizardConfig) (*apiclient.GitRepos CursorIndex: selectionListCursorIdx, } - namespaceId, navigate = selection.GetNamespaceIdFromPrompt(namespaceList, config.ProjectOrder, selectionListOptions) + namespaceId, navigate = selection.GetNamespaceIdFromPrompt(namespaceList, params.WorkspaceOrder, selectionListOptions) if !disablePagination && navigate != "" { if navigate == views.ListNavigationText { @@ -199,7 +197,7 @@ func getRepositoryFromWizard(config RepositoryWizardConfig) (*apiclient.GitRepos // Fetch repos for the current page err = views_util.WithSpinner("Loading Repositories", func() error { - repos, _, err := config.ApiClient.GitProviderAPI.GetRepositories(ctx, gitProviderConfigId, namespaceId).Page(page).PerPage(perPage).Execute() + repos, _, err := params.ApiClient.GitProviderAPI.GetRepositories(ctx, gitProviderConfigId, namespaceId).Page(page).PerPage(perPage).Execute() if err != nil { return err } @@ -229,7 +227,7 @@ func getRepositoryFromWizard(config RepositoryWizardConfig) (*apiclient.GitRepos } // User will either choose a repo or navigate the pages - chosenRepo, navigate = selection.GetRepositoryFromPrompt(providerRepos, config.ProjectOrder, config.SelectedRepos, selectionListOptions) + chosenRepo, navigate = selection.GetRepositoryFromPrompt(providerRepos, params.WorkspaceOrder, params.SelectedRepos, selectionListOptions) if !disablePagination && navigate != "" { if navigate == views.ListNavigationText { page++ @@ -243,17 +241,17 @@ func getRepositoryFromWizard(config RepositoryWizardConfig) (*apiclient.GitRepos } } - if config.SkipBranchSelection { + if params.SkipBranchSelection { return chosenRepo, gitProviderConfigId, nil } - repoWithBranch, err := SetBranchFromWizard(BranchWizardConfig{ - ApiClient: config.ApiClient, + repoWithBranch, err := SetBranchFromWizard(BranchWizardParams{ + ApiClient: params.ApiClient, GitProviderConfigId: gitProviderConfigId, NamespaceId: namespaceId, Namespace: namespace, ChosenRepo: chosenRepo, - ProjectOrder: config.ProjectOrder, + WorkspaceOrder: params.WorkspaceOrder, ProviderId: providerId, }) diff --git a/pkg/cmd/workspace/delete.go b/pkg/cmd/workspace/delete.go index 75b0761321..e97e6172e8 100644 --- a/pkg/cmd/workspace/delete.go +++ b/pkg/cmd/workspace/delete.go @@ -9,10 +9,10 @@ import ( "strings" "github.com/charmbracelet/huh" - "github.com/daytonaio/daytona/cmd/daytona/config" "github.com/daytonaio/daytona/internal/util" apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" "github.com/daytonaio/daytona/pkg/apiclient" + "github.com/daytonaio/daytona/pkg/cmd/common" "github.com/daytonaio/daytona/pkg/views" views_util "github.com/daytonaio/daytona/pkg/views/util" "github.com/daytonaio/daytona/pkg/views/workspace/selection" @@ -24,10 +24,10 @@ var yesFlag bool var forceFlag bool var DeleteCmd = &cobra.Command{ - Use: "delete [WORKSPACE]", + Use: "delete [WORKSPACE]...", Short: "Delete a workspace", - GroupID: util.WORKSPACE_GROUP, - Aliases: []string{"remove", "rm"}, + GroupID: util.TARGET_GROUP, + Aliases: common.GetAliases("delete"), RunE: func(cmd *cobra.Command, args []string) error { if allFlag { if yesFlag { @@ -65,8 +65,7 @@ var DeleteCmd = &cobra.Command{ ctx := context.Background() - var workspaceDeleteList = []*apiclient.WorkspaceDTO{} - var workspaceDeleteListNames = []string{} + var workspaceDeleteList []*apiclient.WorkspaceDTO apiClient, err := apiclient_util.GetApiClient(nil) if err != nil { return err @@ -83,19 +82,15 @@ var DeleteCmd = &cobra.Command{ return nil } - workspaceDeleteList = selection.GetWorkspacesFromPrompt(workspaceList, "Delete") - for _, workspace := range workspaceDeleteList { - workspaceDeleteListNames = append(workspaceDeleteListNames, workspace.Name) - } + workspaceDeleteList = selection.GetWorkspacesFromPrompt(workspaceList, selection.DeleteActionVerb) } else { for _, arg := range args { - workspace, err := apiclient_util.GetWorkspace(arg, false) + workspace, _, err := apiclient_util.GetWorkspace(arg) if err != nil { log.Error(fmt.Sprintf("[ %s ] : %v", arg, err)) continue } workspaceDeleteList = append(workspaceDeleteList, workspace) - workspaceDeleteListNames = append(workspaceDeleteListNames, workspace.Name) } } @@ -103,12 +98,16 @@ var DeleteCmd = &cobra.Command{ return nil } + wsDeleteListNames := util.ArrayMap(workspaceDeleteList, func(w *apiclient.WorkspaceDTO) string { + return w.Name + }) + if !yesFlag { form := huh.NewForm( huh.NewGroup( huh.NewConfirm(). - Title(fmt.Sprintf("Delete workspace(s): [%s]?", strings.Join(workspaceDeleteListNames, ", "))). - Description(fmt.Sprintf("Are you sure you want to delete the workspace(s): [%s]?", strings.Join(workspaceDeleteListNames, ", "))). + Title(fmt.Sprintf("Delete workspace(s): [%s]?", strings.Join(wsDeleteListNames, ", "))). + Description(fmt.Sprintf("Are you sure you want to delete the workspace(s): [%s]?", strings.Join(wsDeleteListNames, ", "))). Value(&yesFlag), ), ).WithTheme(views.GetCustomTheme()) @@ -123,9 +122,10 @@ var DeleteCmd = &cobra.Command{ fmt.Println("Operation canceled.") } else { for _, workspace := range workspaceDeleteList { - err := RemoveWorkspace(ctx, apiClient, workspace, forceFlag) + err := common.DeleteWorkspace(ctx, apiClient, workspace.Id, workspace.Name, forceFlag) if err != nil { log.Error(fmt.Sprintf("[ %s ] : %v", workspace.Name, err)) + continue } views.RenderInfoMessage(fmt.Sprintf("Workspace '%s' successfully deleted", workspace.Name)) } @@ -133,7 +133,7 @@ var DeleteCmd = &cobra.Command{ return nil }, ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - return getWorkspaceNameCompletions() + return common.GetWorkspaceNameCompletions() }, } @@ -156,7 +156,7 @@ func DeleteAllWorkspaces(force bool) error { } for _, workspace := range workspaceList { - err := RemoveWorkspace(ctx, apiClient, &workspace, force) + err := common.DeleteWorkspace(ctx, apiClient, workspace.Id, workspace.Name, force) if err != nil { log.Errorf("Failed to delete workspace %s: %v", workspace.Name, err) continue @@ -165,36 +165,3 @@ func DeleteAllWorkspaces(force bool) error { } return nil } - -func RemoveWorkspace(ctx context.Context, apiClient *apiclient.APIClient, workspace *apiclient.WorkspaceDTO, force bool) error { - message := fmt.Sprintf("Deleting workspace %s", workspace.Name) - err := views_util.WithInlineSpinner(message, func() error { - res, err := apiClient.WorkspaceAPI.RemoveWorkspace(ctx, workspace.Id).Force(force).Execute() - if err != nil { - return apiclient_util.HandleErrorResponse(res, err) - } - c, err := config.GetConfig() - if err != nil { - return err - } - - activeProfile, err := c.GetActiveProfile() - if err != nil { - return err - } - - for _, project := range workspace.Projects { - err = config.RemoveWorkspaceSshEntries(activeProfile.Id, workspace.Id, project.Name) - if err != nil { - return err - } - } - return nil - }) - - if err != nil { - return err - } - - return nil -} diff --git a/pkg/cmd/workspace/info.go b/pkg/cmd/workspace/info.go index 16611c1df4..dfa47f1b60 100644 --- a/pkg/cmd/workspace/info.go +++ b/pkg/cmd/workspace/info.go @@ -9,6 +9,7 @@ import ( "github.com/daytonaio/daytona/internal/util" apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" "github.com/daytonaio/daytona/pkg/apiclient" + "github.com/daytonaio/daytona/pkg/cmd/common" "github.com/daytonaio/daytona/pkg/cmd/format" views_util "github.com/daytonaio/daytona/pkg/views/util" "github.com/daytonaio/daytona/pkg/views/workspace/info" @@ -19,9 +20,9 @@ import ( var InfoCmd = &cobra.Command{ Use: "info [WORKSPACE]", Short: "Show workspace info", - Aliases: []string{"view", "inspect"}, Args: cobra.RangeArgs(0, 1), - GroupID: util.WORKSPACE_GROUP, + GroupID: util.TARGET_GROUP, + Aliases: common.GetAliases("info"), RunE: func(cmd *cobra.Command, args []string) error { ctx := context.Background() @@ -30,10 +31,10 @@ var InfoCmd = &cobra.Command{ return err } - var workspace *apiclient.WorkspaceDTO + var ws *apiclient.WorkspaceDTO if len(args) == 0 { - workspaceList, res, err := apiClient.WorkspaceAPI.ListWorkspaces(ctx).Verbose(true).Execute() + workspaceList, res, err := apiClient.WorkspaceAPI.ListWorkspaces(ctx).Execute() if err != nil { return apiclient_util.HandleErrorResponse(res, err) } @@ -47,33 +48,33 @@ var InfoCmd = &cobra.Command{ format.UnblockStdOut() } - workspace = selection.GetWorkspaceFromPrompt(workspaceList, "View") + ws = selection.GetWorkspaceFromPrompt(workspaceList, "View") if format.FormatFlag != "" { format.BlockStdOut() } } else { - workspace, err = apiclient_util.GetWorkspace(args[0], true) + ws, _, err = apiclient_util.GetWorkspace(args[0]) if err != nil { return err } } - if workspace == nil { + if ws == nil { return nil } if format.FormatFlag != "" { - formattedData := format.NewFormatter(workspace) + formattedData := format.NewFormatter(ws) formattedData.Print() return nil } - info.Render(workspace, "", false) + info.Render(ws, "", false) return nil }, ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - return getWorkspaceNameCompletions() + return common.GetWorkspaceNameCompletions() }, } diff --git a/pkg/cmd/workspace/list.go b/pkg/cmd/workspace/list.go index d37d62e8c7..25bbe1082d 100644 --- a/pkg/cmd/workspace/list.go +++ b/pkg/cmd/workspace/list.go @@ -5,35 +5,45 @@ package workspace import ( "context" + "encoding/json" "github.com/daytonaio/daytona/cmd/daytona/config" "github.com/daytonaio/daytona/internal/util" "github.com/daytonaio/daytona/internal/util/apiclient" - apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" + "github.com/daytonaio/daytona/pkg/cmd/common" "github.com/daytonaio/daytona/pkg/cmd/format" - list_view "github.com/daytonaio/daytona/pkg/views/workspace/list" + "github.com/daytonaio/daytona/pkg/views/workspace/list" "github.com/spf13/cobra" ) -var verbose bool +var labelFilters []string var ListCmd = &cobra.Command{ Use: "list", Short: "List workspaces", - Args: cobra.ExactArgs(0), - Aliases: []string{"ls"}, - GroupID: util.WORKSPACE_GROUP, + Args: cobra.NoArgs, + GroupID: util.TARGET_GROUP, + Aliases: common.GetAliases("list"), RunE: func(cmd *cobra.Command, args []string) error { ctx := context.Background() var specifyGitProviders bool - apiClient, err := apiclient_util.GetApiClient(nil) + apiClient, err := apiclient.GetApiClient(nil) if err != nil { return err } - workspaceList, res, err := apiClient.WorkspaceAPI.ListWorkspaces(ctx).Verbose(verbose).Execute() + labels, err := common.MapKeyValue(labelFilters) + if err != nil { + return err + } + + encoded, err := json.Marshal(labels) + if err != nil { + return err + } + workspaceList, res, err := apiClient.WorkspaceAPI.ListWorkspaces(ctx).Labels(string(encoded)).Execute() if err != nil { return apiclient.HandleErrorResponse(res, err) } @@ -63,13 +73,12 @@ var ListCmd = &cobra.Command{ return err } - list_view.ListWorkspaces(workspaceList, specifyGitProviders, verbose, activeProfile.Name) - + list.ListWorkspaces(workspaceList, specifyGitProviders, activeProfile.Name) return nil }, } func init() { - ListCmd.Flags().BoolVarP(&verbose, "verbose", "v", false, "Show verbose output") + ListCmd.Flags().StringSliceVarP(&labelFilters, "label", "l", nil, "Filter by label") format.RegisterFormatFlag(ListCmd) } diff --git a/pkg/cmd/workspace/logs.go b/pkg/cmd/workspace/logs.go new file mode 100644 index 0000000000..c568661ed8 --- /dev/null +++ b/pkg/cmd/workspace/logs.go @@ -0,0 +1,96 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package workspace + +import ( + "context" + + "github.com/daytonaio/daytona/cmd/daytona/config" + "github.com/daytonaio/daytona/internal/util" + apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" + "github.com/daytonaio/daytona/pkg/apiclient" + "github.com/daytonaio/daytona/pkg/cmd/common" + "github.com/daytonaio/daytona/pkg/cmd/format" + views_util "github.com/daytonaio/daytona/pkg/views/util" + "github.com/daytonaio/daytona/pkg/views/workspace/selection" + "github.com/spf13/cobra" +) + +var followFlag bool + +var LogsCmd = &cobra.Command{ + Use: "logs [WORKSPACE]", + Short: "View the logs of a workspace", + Args: cobra.RangeArgs(0, 2), + GroupID: util.TARGET_GROUP, + Aliases: common.GetAliases("logs"), + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.Background() + + apiClient, err := apiclient_util.GetApiClient(nil) + if err != nil { + return err + } + + c, err := config.GetConfig() + if err != nil { + return err + } + + activeProfile, err := c.GetActiveProfile() + if err != nil { + return err + } + + var ws *apiclient.WorkspaceDTO + + if len(args) == 0 { + workspaceList, res, err := apiClient.WorkspaceAPI.ListWorkspaces(ctx).Execute() + if err != nil { + return apiclient_util.HandleErrorResponse(res, err) + } + + if len(workspaceList) == 0 { + views_util.NotifyEmptyWorkspaceList(true) + return nil + } + + if format.FormatFlag != "" { + format.UnblockStdOut() + } + + ws = selection.GetWorkspaceFromPrompt(workspaceList, "View Logs For") + if format.FormatFlag != "" { + format.BlockStdOut() + } + + } else { + ws, _, err = apiclient_util.GetWorkspace(args[0]) + if err != nil { + return err + } + } + + if ws == nil { + return nil + } + + common.ReadWorkspaceLogs(ctx, common.ReadLogParams{ + Id: ws.Id, + Label: &ws.Name, + ServerUrl: activeProfile.Api.Url, + ApiKey: activeProfile.Api.Key, + Index: util.Pointer(0), + Follow: &followFlag, + }) + return nil + }, + ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return common.GetWorkspaceNameCompletions() + }, +} + +func init() { + LogsCmd.Flags().BoolVarP(&followFlag, "follow", "f", false, "Follow logs") +} diff --git a/pkg/cmd/workspace/restart.go b/pkg/cmd/workspace/restart.go index 200f979c3a..9a5f68fb15 100644 --- a/pkg/cmd/workspace/restart.go +++ b/pkg/cmd/workspace/restart.go @@ -10,21 +10,21 @@ import ( "github.com/daytonaio/daytona/internal/util" apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" "github.com/daytonaio/daytona/pkg/apiclient" + "github.com/daytonaio/daytona/pkg/cmd/common" "github.com/daytonaio/daytona/pkg/views" views_util "github.com/daytonaio/daytona/pkg/views/util" "github.com/daytonaio/daytona/pkg/views/workspace/selection" + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" ) -var restartProjectFlag string - var RestartCmd = &cobra.Command{ - Use: "restart [WORKSPACE]", + Use: "restart [WORKSPACE]...", Short: "Restart a workspace", - Args: cobra.RangeArgs(0, 1), - GroupID: util.WORKSPACE_GROUP, + GroupID: util.TARGET_GROUP, RunE: func(cmd *cobra.Command, args []string) error { - var workspaceId string + var selectedWorkspaces []*apiclient.WorkspaceDTO ctx := context.Background() @@ -33,58 +33,55 @@ var RestartCmd = &cobra.Command{ return err } + workspaceList, res, err := apiClient.WorkspaceAPI.ListWorkspaces(ctx).Execute() + if err != nil { + return apiclient_util.HandleErrorResponse(res, err) + } + + if len(workspaceList) == 0 { + views_util.NotifyEmptyWorkspaceList(true) + return nil + } + if len(args) == 0 { - if restartProjectFlag != "" { - err := cmd.Help() + selectedWorkspaces = selection.GetWorkspacesFromPrompt(workspaceList, selection.RestartActionVerb) + if selectedWorkspaces == nil { + return nil + } + } else { + for _, arg := range args { + workspace, _, err := apiclient_util.GetWorkspace(arg) if err != nil { - return err + log.Error(fmt.Sprintf("[ %s ] : %v", arg, err)) + continue } - return nil + selectedWorkspaces = append(selectedWorkspaces, workspace) } + } - workspaceList, res, err := apiClient.WorkspaceAPI.ListWorkspaces(ctx).Execute() - if err != nil { - return apiclient_util.HandleErrorResponse(res, err) - } + if len(selectedWorkspaces) == 1 { + workspace := selectedWorkspaces[0] - if len(workspaceList) == 0 { - views_util.NotifyEmptyWorkspaceList(true) - return nil + err = StartWorkspace(apiClient, *workspace, true) + if err != nil { + return err } - workspace := selection.GetWorkspaceFromPrompt(workspaceList, "Restart") - if workspace == nil { - return nil - } - workspaceId = workspace.Name + views.RenderInfoMessage(fmt.Sprintf("Workspace '%s' restarted successfully", workspace.Name)) } else { - workspaceId = args[0] + for _, ws := range selectedWorkspaces { + err := StartWorkspace(apiClient, *ws, true) + if err != nil { + log.Errorf("Failed to restart workspace %s: %v\n\n", ws.Name, err) + continue + } + views.RenderInfoMessage(fmt.Sprintf("- Workspace '%s' restarted successfully", ws.Name)) + } } - err = RestartWorkspace(apiClient, workspaceId, restartProjectFlag) - if err != nil { - return err - } - if restartProjectFlag != "" { - views.RenderInfoMessage(fmt.Sprintf("Project '%s' from workspace '%s' successfully restarted", restartProjectFlag, workspaceId)) - } else { - views.RenderInfoMessage(fmt.Sprintf("Workspace '%s' successfully restarted", workspaceId)) - } return nil }, ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - return getAllWorkspacesByState(WORKSPACE_STATUS_RUNNING) + return common.GetAllWorkspacesByState(apiclient.ResourceStateNameStarted) }, } - -func init() { - RestartCmd.Flags().StringVarP(&restartProjectFlag, "project", "p", "", "Restart a single project in the workspace (project name)") -} - -func RestartWorkspace(apiClient *apiclient.APIClient, workspaceId, projectName string) error { - err := StopWorkspace(apiClient, workspaceId, projectName) - if err != nil { - return err - } - return StartWorkspace(apiClient, workspaceId, projectName) -} diff --git a/pkg/cmd/workspace/ssh-proxy.go b/pkg/cmd/workspace/ssh-proxy.go index 194aa31857..0fa5385c29 100644 --- a/pkg/cmd/workspace/ssh-proxy.go +++ b/pkg/cmd/workspace/ssh-proxy.go @@ -7,16 +7,19 @@ import ( "context" "fmt" "io" + "net/http" "os" "time" "github.com/daytonaio/daytona/cmd/daytona/config" "github.com/daytonaio/daytona/internal/cmd/tailscale" - "github.com/daytonaio/daytona/internal/util/apiclient" + apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" "github.com/daytonaio/daytona/internal/util/apiclient/conversion" ssh_config "github.com/daytonaio/daytona/pkg/agent/ssh/config" + "github.com/daytonaio/daytona/pkg/apiclient" + "github.com/daytonaio/daytona/pkg/common" "github.com/daytonaio/daytona/pkg/docker" - "github.com/daytonaio/daytona/pkg/workspace/project" + "github.com/daytonaio/daytona/pkg/models" "github.com/docker/docker/api/types/container" "github.com/docker/docker/client" "github.com/docker/docker/pkg/stdcopy" @@ -26,8 +29,8 @@ import ( ) var SshProxyCmd = &cobra.Command{ - Use: "ssh-proxy [PROFILE_ID] [WORKSPACE_ID] [PROJECT]", - Args: cobra.RangeArgs(2, 3), + Use: "ssh-proxy [PROFILE_ID] [TARGET_ID | WORKSPACE_ID]", + Args: cobra.ExactArgs(2), Hidden: true, RunE: func(cmd *cobra.Command, args []string) error { c, err := config.GetConfig() @@ -36,40 +39,34 @@ var SshProxyCmd = &cobra.Command{ } profileId := args[0] - workspaceId := args[1] - projectName := "" + resourceId := args[1] profile, err := c.GetProfile(profileId) if err != nil { return err } - if len(args) == 3 { - projectName = args[2] + var target *apiclient.TargetDTO + + ws, statusCode, err := apiclient_util.GetWorkspace(resourceId) + if err != nil && statusCode != http.StatusNotFound { + return err + } + + if ws == nil { + target, _, err = apiclient_util.GetTarget(resourceId) + if err != nil { + return err + } } else { - projectName, err = apiclient.GetFirstWorkspaceProjectName(workspaceId, projectName, &profile) + target, _, err = apiclient_util.GetTarget(ws.TargetId) if err != nil { return err } } - workspace, err := apiclient.GetWorkspace(workspaceId, true) - if err != nil { - return err - } - - if workspace.Target == "local" && profile.Id == "default" { - // If the workspace is local, we directly access the ssh port through the container - project := workspace.Projects[0] - - if project.Name != projectName { - for _, p := range workspace.Projects { - if p.Name == projectName { - project = p - break - } - } - } + if ws != nil && common.IsLocalDockerTarget(target.TargetConfig.ProviderInfo.Name, target.TargetConfig.Options, target.TargetConfig.ProviderInfo.RunnerId) && profile.Id == "default" { + // If the target is local, we directly access the ssh port through the container cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) if err != nil { @@ -80,7 +77,12 @@ var SshProxyCmd = &cobra.Command{ ApiClient: cli, }) - containerName := dockerClient.GetProjectContainerName(conversion.ToProject(&project)) + workspace, err := conversion.Convert[apiclient.WorkspaceDTO, models.Workspace](ws) + if err != nil { + return err + } + + containerName := dockerClient.GetWorkspaceContainerName(workspace) ctx := context.Background() @@ -139,7 +141,12 @@ var SshProxyCmd = &cobra.Command{ errChan := make(chan error) - dialConn, err := tsConn.Dial(context.Background(), "tcp", fmt.Sprintf("%s:%d", project.GetProjectHostname(workspaceId, projectName), ssh_config.SSH_PORT)) + hostname := common.GetTailscaleHostname(target.Id) + if ws != nil { + hostname = common.GetTailscaleHostname(ws.Id) + } + + dialConn, err := tsConn.Dial(context.Background(), "tcp", fmt.Sprintf("%s:%d", hostname, ssh_config.SSH_PORT)) if err != nil { return err } diff --git a/pkg/cmd/workspace/ssh.go b/pkg/cmd/workspace/ssh.go index c4322b0454..00b14be40f 100644 --- a/pkg/cmd/workspace/ssh.go +++ b/pkg/cmd/workspace/ssh.go @@ -16,7 +16,7 @@ import ( "github.com/daytonaio/daytona/internal/util" apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" "github.com/daytonaio/daytona/pkg/apiclient" - workspace_util "github.com/daytonaio/daytona/pkg/cmd/workspace/util" + "github.com/daytonaio/daytona/pkg/cmd/common" "github.com/daytonaio/daytona/pkg/ide" "github.com/daytonaio/daytona/pkg/views" views_util "github.com/daytonaio/daytona/pkg/views/util" @@ -31,10 +31,10 @@ var ( ) var SshCmd = &cobra.Command{ - Use: "ssh [WORKSPACE] [PROJECT] [CMD...]", - Short: "SSH into a project using the terminal", + Use: "ssh [WORKSPACE] [CMD...]", + Short: "SSH into a workspace using the terminal", Args: cobra.ArbitraryArgs, - GroupID: util.WORKSPACE_GROUP, + GroupID: util.TARGET_GROUP, RunE: func(cmd *cobra.Command, args []string) error { c, err := config.GetConfig() if err != nil { @@ -47,9 +47,7 @@ var SshCmd = &cobra.Command{ } ctx := context.Background() - var workspace *apiclient.WorkspaceDTO - var projectName string - var providerConfigId *string + var ws *apiclient.WorkspaceDTO apiClient, err := apiclient_util.GetApiClient(&activeProfile) if err != nil { @@ -67,49 +65,27 @@ var SshCmd = &cobra.Command{ return nil } - workspace = selection.GetWorkspaceFromPrompt(workspaceList, "SSH Into") - if workspace == nil { + ws = selection.GetWorkspaceFromPrompt(workspaceList, "SSH Into") + if ws == nil { return nil } } else { - workspace, err = apiclient_util.GetWorkspace(args[0], true) + ws, _, err = apiclient_util.GetWorkspace(args[0]) if err != nil { return err } } - if len(args) == 0 || len(args) == 1 { - selectedProject, err := selectWorkspaceProject(workspace.Id, &activeProfile) - if err != nil { - return err - } - if selectedProject == nil { - return nil - } - projectName = selectedProject.Name - providerConfigId = selectedProject.GitProviderConfigId - } - - if len(args) >= 2 { - projectName = args[1] - for _, project := range workspace.Projects { - if project.Name == projectName { - providerConfigId = project.GitProviderConfigId - break - } - } - } - if edit { - err := editSSHConfig(activeProfile, workspace, projectName) + err := editSSHConfig(activeProfile, ws) if err != nil { return err } return nil } - if !workspace_util.IsProjectRunning(workspace, projectName) { - wsRunningStatus, err := AutoStartWorkspace(workspace.Name, projectName) + if ws.State.Name == apiclient.ResourceStateNameStopped { + wsRunningStatus, err := AutoStartWorkspace(*ws) if err != nil { return err } @@ -119,36 +95,29 @@ var SshCmd = &cobra.Command{ } sshArgs := []string{} - if len(args) > 2 { - sshArgs = append(sshArgs, args[2:]...) + if len(args) > 1 { + sshArgs = append(sshArgs, args[1:]...) } - gpgKey, err := GetGitProviderGpgKey(apiClient, ctx, providerConfigId) + gpgKey, err := common.GetGitProviderGpgKey(apiClient, ctx, ws.GitProviderConfigId) if err != nil { log.Warn(err) } - return ide.OpenTerminalSsh(activeProfile, workspace.Id, projectName, gpgKey, sshOptions, sshArgs...) + return ide.OpenTerminalSsh(activeProfile, ws.Id, gpgKey, sshOptions, sshArgs...) }, ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - if len(args) >= 2 { - return nil, cobra.ShellCompDirectiveNoFileComp - } - if len(args) == 1 { - return getProjectNameCompletions(cmd, args, toComplete) - } - - return getWorkspaceNameCompletions() + return common.GetWorkspaceNameCompletions() }, } func init() { SshCmd.Flags().BoolVarP(&yesFlag, "yes", "y", false, "Automatically confirm any prompts") - SshCmd.Flags().BoolVarP(&edit, "edit", "e", false, "Edit the project's SSH config") + SshCmd.Flags().BoolVarP(&edit, "edit", "e", false, "Edit the workspace's SSH config") SshCmd.Flags().StringArrayVarP(&sshOptions, "option", "o", []string{}, "Specify SSH options in KEY=VALUE format.") } -func editSSHConfig(activeProfile config.Profile, workspace *apiclient.WorkspaceDTO, projectName string) error { +func editSSHConfig(activeProfile config.Profile, workspace *apiclient.WorkspaceDTO) error { sshDir := filepath.Join(config.SshHomeDir, ".ssh") configPath := filepath.Join(sshDir, "daytona_config") sshConfig, err := config.ReadSshConfig(configPath) @@ -156,11 +125,11 @@ func editSSHConfig(activeProfile config.Profile, workspace *apiclient.WorkspaceD return err } - hostLine := fmt.Sprintf("Host %s", config.GetProjectHostname(activeProfile.Id, workspace.Id, projectName)) + hostLine := fmt.Sprintf("Host %s", config.GetHostname(activeProfile.Id, workspace.Id)) regex := regexp.MustCompile(fmt.Sprintf(`%s\s*\n(?:\t.*\n?)*`, hostLine)) matchedEntry := regex.FindString(sshConfig) if matchedEntry == "" { - return fmt.Errorf("no SSH entry found for project %s", projectName) + return fmt.Errorf("no SSH entry found for workspace %s", workspace.Name) } lines := strings.Split(matchedEntry, "\n") @@ -213,11 +182,11 @@ func editSSHConfig(activeProfile config.Profile, workspace *apiclient.WorkspaceD } if modifiedContent == "" { - err = config.RemoveWorkspaceSshEntries(activeProfile.Id, workspace.Id, projectName) + err = config.RemoveSshEntries(activeProfile.Id, workspace.Id) if err != nil { return err } - views.RenderInfoMessage(fmt.Sprintf("SSH configuration for %s removed successfully", projectName)) + views.RenderInfoMessage(fmt.Sprintf("SSH configuration for %s removed successfully", workspace.Name)) return nil } @@ -237,12 +206,12 @@ func editSSHConfig(activeProfile config.Profile, workspace *apiclient.WorkspaceD modifiedContent += "\n" } - err = config.UpdateWorkspaceSshEntry(activeProfile.Id, workspace.Id, projectName, modifiedContent) + err = config.UpdateSshEntry(activeProfile.Id, workspace.Id, modifiedContent) if err != nil { return err } - views.RenderInfoMessage(fmt.Sprintf("SSH configuration for %s updated successfully", projectName)) + views.RenderInfoMessage(fmt.Sprintf("SSH configuration for %s updated successfully", workspace.Name)) return nil } diff --git a/pkg/cmd/workspace/start.go b/pkg/cmd/workspace/start.go index c3e8052974..a49121a873 100644 --- a/pkg/cmd/workspace/start.go +++ b/pkg/cmd/workspace/start.go @@ -6,44 +6,37 @@ package workspace import ( "context" "fmt" + "net/http" "time" "github.com/daytonaio/daytona/cmd/daytona/config" "github.com/daytonaio/daytona/internal/util" apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" "github.com/daytonaio/daytona/pkg/apiclient" - workspace_util "github.com/daytonaio/daytona/pkg/cmd/workspace/util" + "github.com/daytonaio/daytona/pkg/cmd/common" "github.com/daytonaio/daytona/pkg/views" ide_views "github.com/daytonaio/daytona/pkg/views/ide" views_util "github.com/daytonaio/daytona/pkg/views/util" "github.com/daytonaio/daytona/pkg/views/workspace/selection" + log "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) -type WorkspaceState string - -const ( - WORKSPACE_STATUS_RUNNING WorkspaceState = "Running" - WORKSPACE_STATUS_STOPPED WorkspaceState = "Unavailable" -) - -var startProjectFlag string var allFlag bool var codeFlag bool var StartCmd = &cobra.Command{ - Use: "start [WORKSPACE]", + Use: "start [WORKSPACE]...", Short: "Start a workspace", - Args: cobra.RangeArgs(0, 1), - GroupID: util.WORKSPACE_GROUP, + GroupID: util.TARGET_GROUP, RunE: func(cmd *cobra.Command, args []string) error { - var selectedWorkspacesNames []string + var selectedWorkspaces []*apiclient.WorkspaceDTO var activeProfile config.Profile var ideId string var ideList []config.Ide var providerConfigId *string - projectProviderMetadata := "" + workspaceProviderMetadata := "" ctx := context.Background() @@ -57,9 +50,6 @@ var StartCmd = &cobra.Command{ } if len(args) == 0 { - if startProjectFlag != "" { - return cmd.Help() - } workspaceList, res, err := apiClient.WorkspaceAPI.ListWorkspaces(ctx).Execute() if err != nil { return apiclient_util.HandleErrorResponse(res, err) @@ -70,17 +60,22 @@ var StartCmd = &cobra.Command{ return nil } - selectedWorkspaces := selection.GetWorkspacesFromPrompt(workspaceList, "Start") - for _, workspaces := range selectedWorkspaces { - selectedWorkspacesNames = append(selectedWorkspacesNames, workspaces.Name) - } + selectedWorkspaces = selection.GetWorkspacesFromPrompt(workspaceList, selection.StartActionVerb) } else { - selectedWorkspacesNames = append(selectedWorkspacesNames, args[0]) + for _, arg := range args { + workspace, _, err := apiclient_util.GetWorkspace(arg) + if err != nil { + log.Error(fmt.Sprintf("[ %s ] : %v", arg, err)) + continue + } + selectedWorkspaces = append(selectedWorkspaces, workspace) + } } - if len(selectedWorkspacesNames) == 1 { - workspaceName := selectedWorkspacesNames[0] - var workspaceId string + if len(selectedWorkspaces) == 1 { + var ws *apiclient.WorkspaceDTO + var res *http.Response + workspace := selectedWorkspaces[0] if codeFlag { c, err := config.GetConfig() if err != nil { @@ -95,80 +90,54 @@ var StartCmd = &cobra.Command{ ideList = config.GetIdeList() ideId = c.DefaultIdeId - wsInfo, res, err := apiClient.WorkspaceAPI.GetWorkspace(ctx, workspaceName).Execute() + ws, res, err = apiClient.WorkspaceAPI.FindWorkspace(ctx, workspace.Id).Execute() if err != nil { return apiclient_util.HandleErrorResponse(res, err) } - workspaceId = wsInfo.Id - if startProjectFlag == "" { - startProjectFlag = wsInfo.Projects[0].Name - providerConfigId = wsInfo.Projects[0].GitProviderConfigId - } else { - for _, project := range wsInfo.Projects { - if project.Name == startProjectFlag { - providerConfigId = project.GitProviderConfigId - break - } - } - } - if ideId != "ssh" { - projectProviderMetadata, err = workspace_util.GetProjectProviderMetadata(wsInfo, wsInfo.Projects[0].Name) - if err != nil { - return err - } + workspaceProviderMetadata = *ws.ProviderMetadata } } - err = StartWorkspace(apiClient, workspaceName, startProjectFlag) + err = StartWorkspace(apiClient, *workspace, false) if err != nil { return err } - gpgKey, err := GetGitProviderGpgKey(apiClient, ctx, providerConfigId) + gpgKey, err := common.GetGitProviderGpgKey(apiClient, ctx, providerConfigId) if err != nil { log.Warn(err) } - if startProjectFlag == "" { - views.RenderInfoMessage(fmt.Sprintf("Workspace '%s' started successfully", workspaceName)) - } else { - views.RenderInfoMessage(fmt.Sprintf("Project '%s' from workspace '%s' started successfully", startProjectFlag, workspaceName)) - - if codeFlag { - ide_views.RenderIdeOpeningMessage(workspaceName, startProjectFlag, ideId, ideList) - err = openIDE(ideId, activeProfile, workspaceId, startProjectFlag, projectProviderMetadata, yesFlag, gpgKey) - if err != nil { - return err - } + views.RenderInfoMessage(fmt.Sprintf("Workspace '%s' started successfully", workspace.Name)) + + if codeFlag { + ide_views.RenderIdeOpeningMessage(ws.TargetId, ws.Name, ideId, ideList) + err = common.OpenIDE(ideId, activeProfile, ws.Id, workspaceProviderMetadata, yesFlag, gpgKey) + if err != nil { + return err } } } else { - for _, workspace := range selectedWorkspacesNames { - err := StartWorkspace(apiClient, workspace, "") + for _, ws := range selectedWorkspaces { + err := StartWorkspace(apiClient, *ws, false) if err != nil { - log.Errorf("Failed to start workspace %s: %v\n\n", workspace, err) + log.Errorf("Failed to start workspace %s: %v\n\n", ws.Name, err) continue } - views.RenderInfoMessage(fmt.Sprintf("- Workspace '%s' started successfully", workspace)) + views.RenderInfoMessage(fmt.Sprintf("- Workspace '%s' started successfully", ws.Name)) } } return nil }, ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - return getAllWorkspacesByState(WORKSPACE_STATUS_STOPPED) + return common.GetAllWorkspacesByState(apiclient.ResourceStateNameStopped) }, } func init() { - StartCmd.PersistentFlags().StringVarP(&startProjectFlag, "project", "p", "", "Start a single project in the workspace (project name)") - StartCmd.PersistentFlags().BoolVarP(&allFlag, "all", "a", false, "Start all workspaces") - StartCmd.PersistentFlags().BoolVarP(&codeFlag, "code", "c", false, "Open the workspace in the IDE after workspace start") + StartCmd.PersistentFlags().BoolVarP(&allFlag, "all", "a", false, "Start all targets") + StartCmd.PersistentFlags().BoolVarP(&codeFlag, "code", "c", false, "Open the target in the IDE after target start") StartCmd.PersistentFlags().BoolVarP(&yesFlag, "yes", "y", false, "Automatically confirm any prompts") - - err := StartCmd.RegisterFlagCompletionFunc("project", getProjectNameCompletions) - if err != nil { - log.Error("failed to register completion function: ", err) - } } func startAllWorkspaces() error { @@ -184,7 +153,7 @@ func startAllWorkspaces() error { } for _, workspace := range workspaceList { - err := StartWorkspace(apiClient, workspace.Name, "") + err := StartWorkspace(apiClient, workspace, false) if err != nil { log.Errorf("Failed to start workspace %s: %v\n\n", workspace.Name, err) continue @@ -195,81 +164,8 @@ func startAllWorkspaces() error { return nil } -func getProjectNameCompletions(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { +func StartWorkspace(apiClient *apiclient.APIClient, workspace apiclient.WorkspaceDTO, restart bool) error { ctx := context.Background() - apiClient, err := apiclient_util.GetApiClient(nil) - if err != nil { - return nil, cobra.ShellCompDirectiveDefault - } - - workspaceId := args[0] - workspace, _, err := apiClient.WorkspaceAPI.GetWorkspace(ctx, workspaceId).Execute() - if err != nil { - return nil, cobra.ShellCompDirectiveDefault - } - - var choices []string - for _, project := range workspace.Projects { - choices = append(choices, project.Name) - } - return choices, cobra.ShellCompDirectiveDefault -} - -func getWorkspaceNameCompletions() ([]string, cobra.ShellCompDirective) { - ctx := context.Background() - apiClient, err := apiclient_util.GetApiClient(nil) - if err != nil { - return nil, cobra.ShellCompDirectiveNoFileComp - } - - workspaceList, _, err := apiClient.WorkspaceAPI.ListWorkspaces(ctx).Execute() - if err != nil { - return nil, cobra.ShellCompDirectiveNoFileComp - } - - var choices []string - for _, v := range workspaceList { - choices = append(choices, v.Name) - } - - return choices, cobra.ShellCompDirectiveNoFileComp -} - -func getAllWorkspacesByState(state WorkspaceState) ([]string, cobra.ShellCompDirective) { - ctx := context.Background() - apiClient, err := apiclient_util.GetApiClient(nil) - if err != nil { - return nil, cobra.ShellCompDirectiveNoFileComp - } - - workspaceList, _, err := apiClient.WorkspaceAPI.ListWorkspaces(ctx).Execute() - if err != nil { - return nil, cobra.ShellCompDirectiveNoFileComp - } - - var choices []string - for _, workspace := range workspaceList { - for _, project := range workspace.Projects { - if project.State == nil { - continue - } - if state == WORKSPACE_STATUS_RUNNING && project.State.Uptime != 0 { - choices = append(choices, workspace.Name) - break - } - if state == WORKSPACE_STATUS_STOPPED && project.State.Uptime == 0 { - choices = append(choices, workspace.Name) - break - } - } - } - - return choices, cobra.ShellCompDirectiveNoFileComp -} - -func StartWorkspace(apiClient *apiclient.APIClient, workspaceId, projectName string) error { - ctx := context.Background() - var projectNames []string timeFormat := time.Now().Format("2006-01-02 15:04:05") from, err := time.Parse("2006-01-02 15:04:05", timeFormat) if err != nil { @@ -286,38 +182,38 @@ func StartWorkspace(apiClient *apiclient.APIClient, workspaceId, projectName str return err } - workspace, err := apiclient_util.GetWorkspace(workspaceId, false) - if err != nil { - return err - } - if projectName != "" { - projectNames = append(projectNames, projectName) + logsContext, stopLogs := context.WithCancel(context.Background()) + go common.ReadWorkspaceLogs(logsContext, common.ReadLogParams{ + Id: workspace.Id, + Label: &workspace.Name, + ServerUrl: activeProfile.Api.Url, + ApiKey: activeProfile.Api.Key, + Index: util.Pointer(0), + Follow: util.Pointer(true), + From: &from, + }) + + var res *http.Response + + if restart { + res, err = apiClient.WorkspaceAPI.RestartWorkspace(ctx, workspace.Id).Execute() } else { - projectNames = util.ArrayMap(workspace.Projects, func(p apiclient.Project) string { - return p.Name - }) + res, err = apiClient.WorkspaceAPI.StartWorkspace(ctx, workspace.Id).Execute() } - logsContext, stopLogs := context.WithCancel(context.Background()) - go apiclient_util.ReadWorkspaceLogs(logsContext, activeProfile, workspace.Id, projectNames, true, true, &from) - - if projectName == "" { - res, err := apiClient.WorkspaceAPI.StartWorkspace(ctx, workspaceId).Execute() - if err != nil { - stopLogs() - return apiclient_util.HandleErrorResponse(res, err) - } - time.Sleep(100 * time.Millisecond) + if err != nil { stopLogs() - return nil - } else { - res, err := apiClient.WorkspaceAPI.StartProject(ctx, workspaceId, projectName).Execute() - if err != nil { - stopLogs() - return apiclient_util.HandleErrorResponse(res, err) - } - time.Sleep(100 * time.Millisecond) + return apiclient_util.HandleErrorResponse(res, err) + } + + err = common.AwaitWorkspaceState(workspace.Id, apiclient.ResourceStateNameStarted) + if err != nil { stopLogs() - return nil + return err } + + time.Sleep(100 * time.Millisecond) + + stopLogs() + return nil } diff --git a/pkg/cmd/workspace/stop.go b/pkg/cmd/workspace/stop.go index 1c88412f31..eaaa8513ad 100644 --- a/pkg/cmd/workspace/stop.go +++ b/pkg/cmd/workspace/stop.go @@ -12,52 +12,34 @@ import ( "github.com/daytonaio/daytona/internal/util" apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" "github.com/daytonaio/daytona/pkg/apiclient" + "github.com/daytonaio/daytona/pkg/cmd/common" "github.com/daytonaio/daytona/pkg/views" views_util "github.com/daytonaio/daytona/pkg/views/util" "github.com/daytonaio/daytona/pkg/views/workspace/selection" + log "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) -var stopProjectFlag string - var StopCmd = &cobra.Command{ - Use: "stop [WORKSPACE]", + Use: "stop [WORKSPACE]...", Short: "Stop a workspace", - GroupID: util.WORKSPACE_GROUP, - Args: cobra.RangeArgs(0, 1), + GroupID: util.TARGET_GROUP, RunE: func(cmd *cobra.Command, args []string) error { - timeFormat := time.Now().Format("2006-01-02 15:04:05") - from, err := time.Parse("2006-01-02 15:04:05", timeFormat) - if err != nil { - return err - } + var selectedWorkspaces []*apiclient.WorkspaceDTO - c, err := config.GetConfig() - if err != nil { - return err - } + ctx := context.Background() - activeProfile, err := c.GetActiveProfile() + apiClient, err := apiclient_util.GetApiClient(nil) if err != nil { return err } if allFlag { - return stopAllWorkspaces(activeProfile, from) - } - - ctx := context.Background() - - apiClient, err := apiclient_util.GetApiClient(nil) - if err != nil { - return err + return stopAllWorkspaces() } if len(args) == 0 { - if stopProjectFlag != "" { - return cmd.Help() - } workspaceList, res, err := apiClient.WorkspaceAPI.ListWorkspaces(ctx).Execute() if err != nil { return apiclient_util.HandleErrorResponse(res, err) @@ -68,64 +50,50 @@ var StopCmd = &cobra.Command{ return nil } - selectedWorkspaces := selection.GetWorkspacesFromPrompt(workspaceList, "Stop") - - for _, workspace := range selectedWorkspaces { - err := StopWorkspace(apiClient, workspace.Name, "") + selectedWorkspaces = selection.GetWorkspacesFromPrompt(workspaceList, selection.StopActionVerb) + } else { + for _, arg := range args { + workspace, _, err := apiclient_util.GetWorkspace(arg) if err != nil { - log.Errorf("Failed to stop workspace %s: %v\n\n", workspace.Name, err) + log.Error(fmt.Sprintf("[ %s ] : %v", arg, err)) continue } - - projectNames := util.ArrayMap(workspace.Projects, func(p apiclient.Project) string { - return p.Name - }) - apiclient_util.ReadWorkspaceLogs(ctx, activeProfile, workspace.Id, projectNames, false, true, &from) - views.RenderInfoMessage(fmt.Sprintf("- Workspace '%s' successfully stopped", workspace.Name)) + selectedWorkspaces = append(selectedWorkspaces, workspace) } - } else { - workspaceId := args[0] - var projectNames []string + } - err = StopWorkspace(apiClient, workspaceId, stopProjectFlag) - if err != nil { - return err - } + if len(selectedWorkspaces) == 1 { + workspace := selectedWorkspaces[0] - workspace, err := apiclient_util.GetWorkspace(workspaceId, false) + err = StopWorkspace(apiClient, *workspace) if err != nil { return err } - if startProjectFlag != "" { - projectNames = append(projectNames, stopProjectFlag) - } else { - projectNames = util.ArrayMap(workspace.Projects, func(p apiclient.Project) string { - return p.Name - }) - } - - apiclient_util.ReadWorkspaceLogs(ctx, activeProfile, workspace.Id, projectNames, false, true, &from) - - if stopProjectFlag != "" { - views.RenderInfoMessage(fmt.Sprintf("Project '%s' from workspace '%s' successfully stopped", stopProjectFlag, workspaceId)) - } else { - views.RenderInfoMessage(fmt.Sprintf("Workspace '%s' successfully stopped", workspaceId)) + views.RenderInfoMessage(fmt.Sprintf("Workspace '%s' stopped successfully", workspace.Name)) + } else { + for _, ws := range selectedWorkspaces { + err := StopWorkspace(apiClient, *ws) + if err != nil { + log.Errorf("Failed to stop workspace %s: %v\n\n", ws.Name, err) + continue + } + views.RenderInfoMessage(fmt.Sprintf("- Workspace '%s' stopped successfully", ws.Name)) } } return nil }, ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - return getAllWorkspacesByState(WORKSPACE_STATUS_RUNNING) + return common.GetAllWorkspacesByState(apiclient.ResourceStateNameStarted) }, } func init() { - StopCmd.Flags().StringVarP(&stopProjectFlag, "project", "p", "", "Stop a single project in the workspace (project name)") - StopCmd.Flags().BoolVarP(&allFlag, "all", "a", false, "Stop all workspaces") + StopCmd.PersistentFlags().BoolVarP(&allFlag, "all", "a", false, "Stop all targets") + StopCmd.PersistentFlags().BoolVarP(&yesFlag, "yes", "y", false, "Automatically confirm any prompts") } -func stopAllWorkspaces(activeProfile config.Profile, from time.Time) error { +func stopAllWorkspaces() error { ctx := context.Background() apiClient, err := apiclient_util.GetApiClient(nil) if err != nil { @@ -138,51 +106,61 @@ func stopAllWorkspaces(activeProfile config.Profile, from time.Time) error { } for _, workspace := range workspaceList { - err := StopWorkspace(apiClient, workspace.Name, "") + err := StopWorkspace(apiClient, workspace) if err != nil { log.Errorf("Failed to stop workspace %s: %v\n\n", workspace.Name, err) continue } - projectNames := util.ArrayMap(workspace.Projects, func(p apiclient.Project) string { - return p.Name - }) - - apiclient_util.ReadWorkspaceLogs(ctx, activeProfile, workspace.Id, projectNames, false, true, &from) - views.RenderInfoMessage(fmt.Sprintf("- Workspace '%s' successfully stopped", workspace.Name)) + views.RenderInfoMessage(fmt.Sprintf("- Workspace '%s' stopped successfully", workspace.Name)) } return nil } -func StopWorkspace(apiClient *apiclient.APIClient, workspaceId, projectName string) error { +func StopWorkspace(apiClient *apiclient.APIClient, workspace apiclient.WorkspaceDTO) error { ctx := context.Background() - var message string - var stopFunc func() error + timeFormat := time.Now().Format("2006-01-02 15:04:05") + from, err := time.Parse("2006-01-02 15:04:05", timeFormat) + if err != nil { + return err + } - if projectName == "" { - message = fmt.Sprintf("Workspace '%s' is stopping", workspaceId) - stopFunc = func() error { - res, err := apiClient.WorkspaceAPI.StopWorkspace(ctx, workspaceId).Execute() - if err != nil { - return apiclient_util.HandleErrorResponse(res, err) - } - return nil - } - } else { - message = fmt.Sprintf("Project '%s' from workspace '%s' is stopping", projectName, workspaceId) - stopFunc = func() error { - res, err := apiClient.WorkspaceAPI.StopProject(ctx, workspaceId, projectName).Execute() - if err != nil { - return apiclient_util.HandleErrorResponse(res, err) - } - return nil - } + c, err := config.GetConfig() + if err != nil { + return err + } + + activeProfile, err := c.GetActiveProfile() + if err != nil { + return err } - err := views_util.WithInlineSpinner(message, stopFunc) + logsContext, stopLogs := context.WithCancel(context.Background()) + go common.ReadWorkspaceLogs(logsContext, common.ReadLogParams{ + Id: workspace.Id, + Label: &workspace.Name, + ServerUrl: activeProfile.Api.Url, + ApiKey: activeProfile.Api.Key, + Index: util.Pointer(0), + Follow: util.Pointer(true), + From: &from, + }) + + res, err := apiClient.WorkspaceAPI.StopWorkspace(ctx, workspace.Id).Execute() if err != nil { + stopLogs() + return apiclient_util.HandleErrorResponse(res, err) + } + + err = common.AwaitWorkspaceState(workspace.Id, apiclient.ResourceStateNameStopped) + if err != nil { + stopLogs() return err } + // Ensure reading remaining logs is completed + time.Sleep(100 * time.Millisecond) + + stopLogs() return nil } diff --git a/pkg/cmd/workspace/util/add_from_config.go b/pkg/cmd/workspace/util/add_from_config.go deleted file mode 100644 index 30b2de961b..0000000000 --- a/pkg/cmd/workspace/util/add_from_config.go +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package util - -import ( - "context" - - apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" - "github.com/daytonaio/daytona/pkg/apiclient" - "github.com/daytonaio/daytona/pkg/common" -) - -func AddProjectFromConfig(projectConfig *apiclient.ProjectConfig, apiClient *apiclient.APIClient, projects *[]apiclient.CreateProjectDTO, branchFlag *string) (*string, error) { - chosenBranchName := "" - if branchFlag != nil { - chosenBranchName = *branchFlag - } - - if chosenBranchName == "" { - chosenBranch, err := GetBranchFromProjectConfig(projectConfig, apiClient, 0) - if err != nil { - return nil, err - } - if chosenBranch == nil { - return nil, common.ErrCtrlCAbort - } - - chosenBranchName = chosenBranch.Name - } - - configRepo, res, err := apiClient.GitProviderAPI.GetGitContext(context.Background()).Repository(apiclient.GetRepositoryContext{ - Url: projectConfig.RepositoryUrl, - Branch: &chosenBranchName, - }).Execute() - if err != nil { - return nil, apiclient_util.HandleErrorResponse(res, err) - } - - project := &apiclient.CreateProjectDTO{ - Name: projectConfig.Name, - GitProviderConfigId: projectConfig.GitProviderConfigId, - Source: apiclient.CreateProjectSourceDTO{ - Repository: *configRepo, - }, - BuildConfig: projectConfig.BuildConfig, - Image: &projectConfig.Image, - User: &projectConfig.User, - EnvVars: projectConfig.EnvVars, - } - *projects = append(*projects, *project) - - return &projectConfig.Name, nil -} diff --git a/pkg/cmd/workspace/util/creation_data.go b/pkg/cmd/workspace/util/creation_data.go deleted file mode 100644 index ac1edeb3a6..0000000000 --- a/pkg/cmd/workspace/util/creation_data.go +++ /dev/null @@ -1,348 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package util - -import ( - "context" - "fmt" - "net/http" - "net/url" - "path/filepath" - "regexp" - "slices" - "strconv" - "strings" - - apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" - "github.com/daytonaio/daytona/pkg/apiclient" - "github.com/daytonaio/daytona/pkg/common" - views_util "github.com/daytonaio/daytona/pkg/views/util" - "github.com/daytonaio/daytona/pkg/views/workspace/create" - "github.com/daytonaio/daytona/pkg/views/workspace/selection" -) - -type ProjectsDataPromptConfig struct { - UserGitProviders []apiclient.GitProvider - ProjectConfigs []apiclient.ProjectConfig - Manual bool - SkipBranchSelection bool - MultiProject bool - BlankProject bool - ApiClient *apiclient.APIClient - Defaults *views_util.ProjectConfigDefaults -} - -func GetProjectsCreationDataFromPrompt(config ProjectsDataPromptConfig) ([]apiclient.CreateProjectDTO, error) { - var projectList []apiclient.CreateProjectDTO - // keep track of visited repos, will help in keeping project names unique - // since these are later saved into the db under a unique constraint field. - selectedRepos := make(map[string]int) - - for i := 1; config.MultiProject || i == 1; i++ { - var err error - - if i > 2 { - addMore, err := create.RunAddMoreProjectsForm() - if err != nil { - return nil, err - } - if !addMore { - break - } - } - - if len(config.ProjectConfigs) > 0 && !config.BlankProject { - projectConfig := selection.GetProjectConfigFromPrompt(config.ProjectConfigs, i, true, false, "Use") - if projectConfig == nil { - return nil, common.ErrCtrlCAbort - } - - projectNames := []string{} - for _, p := range projectList { - projectNames = append(projectNames, p.Name) - } - - // Append occurence number to keep duplicate entries unique - repoUrl := projectConfig.RepositoryUrl - if len(selectedRepos) > 0 && selectedRepos[repoUrl] > 1 { - projectConfig.Name += strconv.Itoa(selectedRepos[repoUrl]) - } - - if projectConfig.Name != selection.BlankProjectIdentifier { - projectName := GetSuggestedName(projectConfig.Name, projectNames) - - getRepoContext := apiclient.GetRepositoryContext{ - Url: projectConfig.RepositoryUrl, - } - - branch, err := GetBranchFromProjectConfig(projectConfig, config.ApiClient, i) - if err != nil { - return nil, err - } - - if branch != nil { - getRepoContext.Branch = &branch.Name - getRepoContext.Sha = &branch.Sha - } - - configRepo, res, err := config.ApiClient.GitProviderAPI.GetGitContext(context.Background()).Repository(getRepoContext).Execute() - if err != nil { - return nil, apiclient_util.HandleErrorResponse(res, err) - } - - createProjectDto := apiclient.CreateProjectDTO{ - Name: projectName, - GitProviderConfigId: projectConfig.GitProviderConfigId, - Source: apiclient.CreateProjectSourceDTO{ - Repository: *configRepo, - }, - BuildConfig: projectConfig.BuildConfig, - Image: config.Defaults.Image, - User: config.Defaults.ImageUser, - EnvVars: projectConfig.EnvVars, - } - - if projectConfig.Image != "" { - createProjectDto.Image = &projectConfig.Image - } - - if projectConfig.User != "" { - createProjectDto.User = &projectConfig.User - } - - if projectConfig.GitProviderConfigId == nil || *projectConfig.GitProviderConfigId == "" { - gitProviderConfigId, res, err := config.ApiClient.GitProviderAPI.GetGitProviderIdForUrl(context.Background(), url.QueryEscape(projectConfig.RepositoryUrl)).Execute() - if err != nil { - return nil, apiclient_util.HandleErrorResponse(res, err) - } - createProjectDto.GitProviderConfigId = &gitProviderConfigId - } - - projectList = append(projectList, createProjectDto) - continue - } - } - - providerRepo, gitProviderConfigId, err := getRepositoryFromWizard(RepositoryWizardConfig{ - ApiClient: config.ApiClient, - UserGitProviders: config.UserGitProviders, - Manual: config.Manual, - MultiProject: config.MultiProject, - SkipBranchSelection: config.SkipBranchSelection, - ProjectOrder: i, - SelectedRepos: selectedRepos, - }) - if err != nil { - return nil, err - } - - if gitProviderConfigId == selection.CustomRepoIdentifier || gitProviderConfigId == selection.CREATE_FROM_SAMPLE { - gitProviderConfigs, res, err := config.ApiClient.GitProviderAPI.ListGitProvidersForUrl(context.Background(), url.QueryEscape(providerRepo.Url)).Execute() - if err != nil { - return nil, apiclient_util.HandleErrorResponse(res, err) - } - - if len(gitProviderConfigs) == 1 { - gitProviderConfigId = gitProviderConfigs[0].Id - } else if len(gitProviderConfigs) > 1 { - gp := selection.GetGitProviderConfigFromPrompt(selection.GetGitProviderConfigParams{ - GitProviderConfigs: gitProviderConfigs, - ActionVerb: "Use", - }) - if gp == nil { - return nil, common.ErrCtrlCAbort - } - gitProviderConfigId = gp.Id - } else { - gitProviderConfigId = "" - } - } - - getRepoContext := createGetRepoContextFromRepository(providerRepo) - - var res *http.Response - providerRepo, res, err = config.ApiClient.GitProviderAPI.GetGitContext(context.Background()).Repository(getRepoContext).Execute() - if err != nil { - return nil, apiclient_util.HandleErrorResponse(res, err) - } - - providerRepoName, err := GetSanitizedProjectName(providerRepo.Name) - if err != nil { - return nil, err - } - - projectList = append(projectList, newCreateProjectConfigDTO(config, providerRepo, providerRepoName, gitProviderConfigId)) - } - - return projectList, nil -} - -func GetProjectNameFromRepo(repoUrl string) string { - projectNameSlugRegex := regexp.MustCompile(`[^a-zA-Z0-9-]`) - return projectNameSlugRegex.ReplaceAllString(strings.TrimSuffix(strings.ToLower(filepath.Base(repoUrl)), ".git"), "-") -} - -func GetSuggestedName(initialSuggestion string, existingNames []string) string { - suggestion := initialSuggestion - - if !slices.Contains(existingNames, suggestion) { - return suggestion - } else { - i := 2 - for { - newSuggestion := fmt.Sprintf("%s%d", suggestion, i) - if !slices.Contains(existingNames, newSuggestion) { - return newSuggestion - } - i++ - } - } -} - -func GetSanitizedProjectName(projectName string) (string, error) { - projectName, err := url.QueryUnescape(projectName) - if err != nil { - return "", err - } - projectName = strings.ReplaceAll(projectName, " ", "-") - - return projectName, nil -} - -func GetBranchFromProjectConfig(projectConfig *apiclient.ProjectConfig, apiClient *apiclient.APIClient, projectOrder int) (*apiclient.GitBranch, error) { - ctx := context.Background() - - encodedURLParam := url.QueryEscape(projectConfig.RepositoryUrl) - - repoResponse, res, err := apiClient.GitProviderAPI.GetGitContext(ctx).Repository(apiclient.GetRepositoryContext{ - Url: projectConfig.RepositoryUrl, - }).Execute() - if err != nil { - return nil, apiclient_util.HandleErrorResponse(res, err) - } - - gitProviderConfigId, res, err := apiClient.GitProviderAPI.GetGitProviderIdForUrl(ctx, encodedURLParam).Execute() - if err != nil { - return nil, apiclient_util.HandleErrorResponse(res, err) - } - - branchWizardConfig := BranchWizardConfig{ - ApiClient: apiClient, - GitProviderConfigId: gitProviderConfigId, - NamespaceId: repoResponse.Owner, - ChosenRepo: repoResponse, - ProjectOrder: projectOrder, - } - - repo, err := SetBranchFromWizard(branchWizardConfig) - if err != nil { - return nil, err - } - - if repo == nil { - return nil, common.ErrCtrlCAbort - } - - return &apiclient.GitBranch{ - Name: repo.Branch, - Sha: repo.Sha, - }, nil -} - -func GetCreateProjectDtoFromFlags(projectConfigurationFlags ProjectConfigurationFlags) (*apiclient.CreateProjectDTO, error) { - project := &apiclient.CreateProjectDTO{ - GitProviderConfigId: projectConfigurationFlags.GitProviderConfig, - BuildConfig: &apiclient.BuildConfig{}, - } - - if *projectConfigurationFlags.Builder == views_util.DEVCONTAINER || *projectConfigurationFlags.DevcontainerPath != "" { - devcontainerFilePath := create.DEVCONTAINER_FILEPATH - if *projectConfigurationFlags.DevcontainerPath != "" { - devcontainerFilePath = *projectConfigurationFlags.DevcontainerPath - } - project.BuildConfig.Devcontainer = &apiclient.DevcontainerConfig{ - FilePath: devcontainerFilePath, - } - - } - - if *projectConfigurationFlags.Builder == views_util.NONE || *projectConfigurationFlags.CustomImage != "" || *projectConfigurationFlags.CustomImageUser != "" { - project.BuildConfig = nil - if *projectConfigurationFlags.CustomImage != "" || *projectConfigurationFlags.CustomImageUser != "" { - project.Image = projectConfigurationFlags.CustomImage - project.User = projectConfigurationFlags.CustomImageUser - } - } - - envVars := make(map[string]string) - - for _, envVar := range *projectConfigurationFlags.EnvVars { - parts := strings.SplitN(envVar, "=", 2) - if len(parts) == 2 { - envVars[parts[0]] = parts[1] - } else { - return nil, fmt.Errorf("Invalid environment variable format: %s\n", envVar) - } - } - - project.EnvVars = envVars - - return project, nil -} - -func GetGitProviderConfigIdFromFlag(ctx context.Context, apiClient *apiclient.APIClient, gitProviderConfigFlag *string) (*string, error) { - if gitProviderConfigFlag == nil || *gitProviderConfigFlag == "" { - return gitProviderConfigFlag, nil - } - - gitProviderConfigs, res, err := apiClient.GitProviderAPI.ListGitProviders(ctx).Execute() - if err != nil { - return nil, apiclient_util.HandleErrorResponse(res, err) - } - - for _, gitProviderConfig := range gitProviderConfigs { - if gitProviderConfig.Id == *gitProviderConfigFlag { - return &gitProviderConfig.Id, nil - } - if gitProviderConfig.Alias == *gitProviderConfigFlag { - return &gitProviderConfig.Id, nil - } - } - - return nil, fmt.Errorf("git provider config '%s' not found", *gitProviderConfigFlag) -} - -func newCreateProjectConfigDTO(config ProjectsDataPromptConfig, providerRepo *apiclient.GitRepository, providerRepoName string, gitProviderConfigId string) apiclient.CreateProjectDTO { - project := apiclient.CreateProjectDTO{ - Name: providerRepoName, - GitProviderConfigId: &gitProviderConfigId, - Source: apiclient.CreateProjectSourceDTO{ - Repository: *providerRepo, - }, - BuildConfig: &apiclient.BuildConfig{}, - Image: config.Defaults.Image, - User: config.Defaults.ImageUser, - EnvVars: map[string]string{}, - } - - return project -} - -func createGetRepoContextFromRepository(providerRepo *apiclient.GitRepository) apiclient.GetRepositoryContext { - result := apiclient.GetRepositoryContext{ - Id: &providerRepo.Id, - Name: &providerRepo.Name, - Owner: &providerRepo.Owner, - Sha: &providerRepo.Sha, - Source: &providerRepo.Source, - Url: providerRepo.Url, - Branch: &providerRepo.Branch, - } - - if providerRepo.Path != nil { - result.Path = providerRepo.Path - } - - return result -} diff --git a/pkg/cmd/workspace/util/get_target.go b/pkg/cmd/workspace/util/get_target.go deleted file mode 100644 index 49b397ed9e..0000000000 --- a/pkg/cmd/workspace/util/get_target.go +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package util - -import ( - "context" - "errors" - "fmt" - - "github.com/daytonaio/daytona/internal/util" - apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" - "github.com/daytonaio/daytona/pkg/apiclient" - "github.com/daytonaio/daytona/pkg/cmd/provider" - "github.com/daytonaio/daytona/pkg/provider/manager" - provider_view "github.com/daytonaio/daytona/pkg/views/provider" - target_view "github.com/daytonaio/daytona/pkg/views/target" -) - -type GetTargetConfig struct { - Ctx context.Context - ApiClient *apiclient.APIClient - TargetList []apiclient.ProviderTarget - ActiveProfileName string - TargetNameFlag string - PromptUsingTUI bool -} - -func GetTarget(config GetTargetConfig) (*target_view.TargetView, error) { - if config.TargetNameFlag != "" { - for _, t := range config.TargetList { - if t.Name == config.TargetNameFlag { - return util.Pointer(target_view.GetTargetViewFromTarget(t)), nil - } - } - return nil, fmt.Errorf("target '%s' not found", config.TargetNameFlag) - } - - if !config.PromptUsingTUI { - for _, t := range config.TargetList { - if t.IsDefault { - return util.Pointer(target_view.GetTargetViewFromTarget(t)), nil - } - } - } - - serverConfig, res, err := config.ApiClient.ServerAPI.GetConfigExecute(apiclient.ApiGetConfigRequest{}) - if err != nil { - return nil, apiclient_util.HandleErrorResponse(res, err) - } - - providersManifest, err := manager.NewProviderManager(manager.ProviderManagerConfig{ - RegistryUrl: serverConfig.RegistryUrl, - }).GetProvidersManifest() - if err != nil { - return nil, err - } - - var providerViewList []provider_view.ProviderView - if providersManifest != nil { - providersManifestLatest := providersManifest.GetLatestVersions() - if providersManifestLatest == nil { - return nil, errors.New("could not get latest provider versions") - } - - latestProviders := provider.GetProviderListFromManifest(providersManifestLatest) - - providerViewList, err = provider.GetProviderViewOptions(config.ApiClient, latestProviders, config.Ctx) - if err != nil { - return nil, err - } - } - - selectedTarget, err := target_view.GetTargetFromPrompt(config.TargetList, config.ActiveProfileName, &providerViewList, false, "Use") - if err != nil { - return nil, err - } - - if selectedTarget.ProviderInfo.Installed == nil || *selectedTarget.ProviderInfo.Installed || selectedTarget == nil { - return selectedTarget, nil - } - - err = provider.InstallProvider(config.ApiClient, provider_view.ProviderView{ - Name: selectedTarget.ProviderInfo.Name, - Version: selectedTarget.ProviderInfo.Version, - }, providersManifest) - if err != nil { - return nil, err - } - - targetManifest, res, err := config.ApiClient.ProviderAPI.GetTargetManifest(context.Background(), selectedTarget.ProviderInfo.Name).Execute() - if err != nil { - return nil, apiclient_util.HandleErrorResponse(res, err) - } - - selectedTarget.Name = "" - err = target_view.NewTargetNameInput(&selectedTarget.Name, util.ArrayMap(config.TargetList, func(t apiclient.ProviderTarget) string { - return t.Name - })) - if err != nil { - return nil, err - } - - err = target_view.SetTargetForm(selectedTarget, *targetManifest) - if err != nil { - return nil, err - } - - res, err = config.ApiClient.TargetAPI.SetTarget(context.Background()).Target(apiclient.CreateProviderTargetDTO{ - Name: selectedTarget.Name, - Options: selectedTarget.Options, - ProviderInfo: apiclient.ProviderProviderInfo{ - Name: selectedTarget.ProviderInfo.Name, - Version: selectedTarget.ProviderInfo.Version, - }, - }).Execute() - if err != nil { - return nil, apiclient_util.HandleErrorResponse(res, err) - } - - return selectedTarget, nil -} diff --git a/pkg/cmd/workspacemode/info.go b/pkg/cmd/workspacemode/info.go deleted file mode 100644 index 10137d2a50..0000000000 --- a/pkg/cmd/workspacemode/info.go +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package workspacemode - -import ( - "github.com/daytonaio/daytona/internal/util" - apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" - "github.com/daytonaio/daytona/pkg/apiclient" - "github.com/daytonaio/daytona/pkg/cmd/format" - "github.com/daytonaio/daytona/pkg/views/workspace/info" - "github.com/spf13/cobra" -) - -var infoCmd = &cobra.Command{ - Use: "info", - Short: "Show project info", - Aliases: []string{"view", "inspect"}, - Args: cobra.ExactArgs(0), - GroupID: util.WORKSPACE_GROUP, - RunE: func(cmd *cobra.Command, args []string) error { - var workspace *apiclient.WorkspaceDTO - - workspace, err := apiclient_util.GetWorkspace(workspaceId, true) - if err != nil { - return err - } - - if workspace == nil { - return nil - } - - if format.FormatFlag != "" { - formattedData := format.NewFormatter(workspace) - formattedData.Print() - return nil - } - - info.Render(workspace, "", false) - return nil - }, -} - -func init() { - format.RegisterFormatFlag(infoCmd) -} diff --git a/pkg/cmd/workspacemode/restart.go b/pkg/cmd/workspacemode/restart.go deleted file mode 100644 index 466c6d47b4..0000000000 --- a/pkg/cmd/workspacemode/restart.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package workspacemode - -import ( - "fmt" - - "github.com/daytonaio/daytona/internal/util" - "github.com/daytonaio/daytona/internal/util/apiclient" - workspace_cmd "github.com/daytonaio/daytona/pkg/cmd/workspace" - "github.com/daytonaio/daytona/pkg/views" - "github.com/spf13/cobra" -) - -var restartCmd = &cobra.Command{ - Use: "restart", - Short: "Restart the project", - Args: cobra.NoArgs, - GroupID: util.WORKSPACE_GROUP, - RunE: func(cmd *cobra.Command, args []string) error { - apiClient, err := apiclient.GetApiClient(nil) - if err != nil { - return err - } - - err = workspace_cmd.RestartWorkspace(apiClient, workspaceId, projectName) - if err != nil { - return err - } - - if projectName != "" { - views.RenderInfoMessage(fmt.Sprintf("Project '%s' from workspace '%s' successfully restarted", projectName, workspaceId)) - } else { - views.RenderInfoMessage(fmt.Sprintf("Workspace '%s' successfully restarted", workspaceId)) - } - return nil - }, -} diff --git a/pkg/cmd/workspacemode/start.go b/pkg/cmd/workspacemode/start.go deleted file mode 100644 index 2473068e82..0000000000 --- a/pkg/cmd/workspacemode/start.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package workspacemode - -import ( - "github.com/daytonaio/daytona/internal/util" - "github.com/daytonaio/daytona/internal/util/apiclient" - workspace_cmd "github.com/daytonaio/daytona/pkg/cmd/workspace" - "github.com/daytonaio/daytona/pkg/views" - "github.com/spf13/cobra" -) - -var startCmd = &cobra.Command{ - Use: "start", - Short: "Start the project", - Args: cobra.NoArgs, - GroupID: util.WORKSPACE_GROUP, - RunE: func(cmd *cobra.Command, args []string) error { - apiClient, err := apiclient.GetApiClient(nil) - if err != nil { - return err - } - - err = workspace_cmd.StartWorkspace(apiClient, workspaceId, projectName) - if err != nil { - return err - } - - views.RenderInfoMessage("Project successfully started") - return nil - }, -} diff --git a/pkg/cmd/workspacemode/stop.go b/pkg/cmd/workspacemode/stop.go deleted file mode 100644 index f11e885ece..0000000000 --- a/pkg/cmd/workspacemode/stop.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package workspacemode - -import ( - "fmt" - - "github.com/daytonaio/daytona/internal/util" - "github.com/daytonaio/daytona/internal/util/apiclient" - workspace_cmd "github.com/daytonaio/daytona/pkg/cmd/workspace" - "github.com/daytonaio/daytona/pkg/views" - "github.com/spf13/cobra" -) - -var stopCmd = &cobra.Command{ - Use: "stop", - Short: "Stop the project", - Args: cobra.NoArgs, - GroupID: util.WORKSPACE_GROUP, - RunE: func(cmd *cobra.Command, args []string) error { - apiClient, err := apiclient.GetApiClient(nil) - if err != nil { - return err - } - - err = workspace_cmd.StopWorkspace(apiClient, workspaceId, projectName) - if err != nil { - return err - } - - if projectName != "" { - views.RenderInfoMessage(fmt.Sprintf("Project '%s' from workspace '%s' successfully stopped", projectName, workspaceId)) - } else { - views.RenderInfoMessage(fmt.Sprintf("Workspace '%s' successfully stopped", workspaceId)) - } - return nil - }, -} diff --git a/pkg/cmd/workspacemode/workspace_mode.go b/pkg/cmd/workspacemode/workspace_mode.go deleted file mode 100644 index aa06f70a57..0000000000 --- a/pkg/cmd/workspacemode/workspace_mode.go +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package workspacemode - -import ( - "os" - "time" - - "github.com/daytonaio/daytona/cmd/daytona/config" - "github.com/daytonaio/daytona/internal/util" - cmd "github.com/daytonaio/daytona/pkg/cmd" - . "github.com/daytonaio/daytona/pkg/cmd/agent" - - "github.com/spf13/cobra" -) - -var workspaceId = "" -var projectName = "" - -var workspaceModeRootCmd = &cobra.Command{ - Use: "daytona", - Short: "Use the Daytona CLI to manage your workspace", - Long: "Use the Daytona CLI to manage your workspace", - DisableAutoGenTag: true, - SilenceUsage: true, - SilenceErrors: true, - RunE: func(cmd *cobra.Command, args []string) error { - return cmd.Help() - }, -} - -func Execute() error { - cmd.SetupRootCommand(workspaceModeRootCmd) - workspaceModeRootCmd.AddGroup(&cobra.Group{ID: util.WORKSPACE_GROUP, Title: "Project & Workspace"}) - workspaceModeRootCmd.AddCommand(gitCredCmd) - workspaceModeRootCmd.AddCommand(AgentCmd) - workspaceModeRootCmd.AddCommand(startCmd) - workspaceModeRootCmd.AddCommand(stopCmd) - workspaceModeRootCmd.AddCommand(restartCmd) - workspaceModeRootCmd.AddCommand(infoCmd) - workspaceModeRootCmd.AddCommand(portForwardCmd) - workspaceModeRootCmd.AddCommand(exposeCmd) - - clientId := config.GetClientId() - telemetryEnabled := config.TelemetryEnabled() - startTime := time.Now() - - telemetryService, command, flags, isComplete, err := cmd.PreRun(workspaceModeRootCmd, os.Args[1:], telemetryEnabled, clientId, startTime) - if err != nil { - return err - } - - err = workspaceModeRootCmd.Execute() - - endTime := time.Now() - if !isComplete { - cmd.PostRun(command, err, telemetryService, clientId, startTime, endTime, flags) - } - - return err -} - -func init() { - if workspaceIdEnv := os.Getenv("DAYTONA_WS_ID"); workspaceIdEnv != "" { - workspaceId = workspaceIdEnv - } - if projectNameEnv := os.Getenv("DAYTONA_WS_PROJECT_NAME"); projectNameEnv != "" { - projectName = projectNameEnv - } -} diff --git a/pkg/cmd/workspacetemplate/create.go b/pkg/cmd/workspacetemplate/create.go new file mode 100644 index 0000000000..f42a8b2214 --- /dev/null +++ b/pkg/cmd/workspacetemplate/create.go @@ -0,0 +1,295 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package workspacetemplate + +import ( + "context" + "errors" + "fmt" + "net/url" + + "github.com/daytonaio/daytona/internal/util" + apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" + "github.com/daytonaio/daytona/pkg/apiclient" + cmd_common "github.com/daytonaio/daytona/pkg/cmd/common" + create_cmd "github.com/daytonaio/daytona/pkg/cmd/workspace/create" + "github.com/daytonaio/daytona/pkg/common" + "github.com/daytonaio/daytona/pkg/views" + views_util "github.com/daytonaio/daytona/pkg/views/util" + "github.com/daytonaio/daytona/pkg/views/workspace/create" + "github.com/spf13/cobra" +) + +var createCmd = &cobra.Command{ + Use: "create", + Short: "Create a workspace template", + Args: cobra.MaximumNArgs(1), + Aliases: cmd_common.GetAliases("create"), + RunE: func(cmd *cobra.Command, args []string) error { + var workspaceTemplate *apiclient.WorkspaceTemplate + var workspaceTemplateName *string + ctx := context.Background() + + apiClient, err := apiclient_util.GetApiClient(nil) + if err != nil { + return err + } + + gitProviders, res, err := apiClient.GitProviderAPI.ListGitProviders(ctx).Execute() + if err != nil { + return apiclient_util.HandleErrorResponse(res, err) + } + + if len(args) == 0 { + workspaceTemplate, err = RunWorkspaceTemplateAddFlow(apiClient, gitProviders, ctx) + if err != nil { + return err + } + if workspaceTemplate == nil { + return nil + } + workspaceTemplateName = &workspaceTemplate.Name + } else { + workspaceTemplateName, err = processCmdArgument(args[0], apiClient, ctx) + if err != nil { + return err + } + } + + if workspaceTemplateName == nil { + return errors.New("workspace template name is required") + } + + views.RenderInfoMessage(fmt.Sprintf("Workspace template %s added successfully", *workspaceTemplateName)) + return nil + }, +} + +func RunWorkspaceTemplateAddFlow(apiClient *apiclient.APIClient, gitProviders []apiclient.GitProvider, ctx context.Context) (*apiclient.WorkspaceTemplate, error) { + if cmd_common.CheckAnyWorkspaceConfigurationFlagSet(workspaceConfigurationFlags) { + return nil, errors.New("please provide the repository URL in order to set up custom workspace template details through the CLI") + } + + var createDtos []apiclient.CreateWorkspaceDTO + existingWorkspaceTemplateNames, err := getExistingWorkspaceTemplateNames(apiClient) + if err != nil { + return nil, err + } + + apiServerConfig, res, err := apiClient.ServerAPI.GetConfig(context.Background()).Execute() + if err != nil { + return nil, apiclient_util.HandleErrorResponse(res, err) + } + + workspaceDefaults := &views_util.WorkspaceTemplateDefaults{ + BuildChoice: views_util.AUTOMATIC, + Image: &apiServerConfig.DefaultWorkspaceImage, + ImageUser: &apiServerConfig.DefaultWorkspaceUser, + DevcontainerFilePath: create.DEVCONTAINER_FILEPATH, + } + + createDtos, err = create_cmd.GetWorkspacesCreationDataFromPrompt(ctx, create_cmd.WorkspacesDataPromptParams{ + UserGitProviders: gitProviders, + Manual: *workspaceConfigurationFlags.Manual, + MultiWorkspace: false, + SkipBranchSelection: true, + ApiClient: apiClient, + Defaults: workspaceDefaults, + }) + + if err != nil { + if common.IsCtrlCAbort(err) { + return nil, nil + } else { + return nil, err + } + } + + create.WorkspacesConfigurationChanged, err = create.RunWorkspaceConfiguration(&createDtos, *workspaceDefaults, false) + if err != nil { + return nil, err + } + + if len(createDtos) == 0 { + return nil, errors.New("no workspaces found") + } + + if createDtos[0].Name == "" { + return nil, errors.New("workspace template name is required") + } + + initialSuggestion := createDtos[0].Name + + chosenName := create_cmd.GetSuggestedName(initialSuggestion, existingWorkspaceTemplateNames) + + submissionFormConfig := create.SubmissionFormParams{ + ChosenName: &chosenName, + SuggestedName: chosenName, + ExistingWorkspaceNames: existingWorkspaceTemplateNames, + WorkspaceList: &createDtos, + NameLabel: "Workspace Template", + Defaults: workspaceDefaults, + } + + err = create.RunSubmissionForm(submissionFormConfig) + if err != nil { + return nil, err + } + + createWorkspaceTemplate := apiclient.CreateWorkspaceTemplateDTO{ + Name: chosenName, + BuildConfig: createDtos[0].BuildConfig, + Image: createDtos[0].Image, + User: createDtos[0].User, + RepositoryUrl: createDtos[0].Source.Repository.Url, + EnvVars: createDtos[0].EnvVars, + GitProviderConfigId: createDtos[0].GitProviderConfigId, + } + + res, err = apiClient.WorkspaceTemplateAPI.SaveWorkspaceTemplate(ctx).WorkspaceTemplate(createWorkspaceTemplate).Execute() + if err != nil { + return nil, apiclient_util.HandleErrorResponse(res, err) + } + + workspaceTemplate := apiclient.WorkspaceTemplate{ + BuildConfig: createWorkspaceTemplate.BuildConfig, + Default: false, + EnvVars: createWorkspaceTemplate.EnvVars, + Name: createWorkspaceTemplate.Name, + Prebuilds: nil, + RepositoryUrl: createWorkspaceTemplate.RepositoryUrl, + GitProviderConfigId: createWorkspaceTemplate.GitProviderConfigId, + } + + if createWorkspaceTemplate.Image != nil { + workspaceTemplate.Image = *createWorkspaceTemplate.Image + } + + if createWorkspaceTemplate.User != nil { + workspaceTemplate.User = *createWorkspaceTemplate.User + } + + if createWorkspaceTemplate.GitProviderConfigId == nil && *createWorkspaceTemplate.GitProviderConfigId == "" { + gitProviderConfigId, res, err := apiClient.GitProviderAPI.FindGitProviderIdForUrl(ctx, url.QueryEscape(createWorkspaceTemplate.RepositoryUrl)).Execute() + if err != nil { + return nil, apiclient_util.HandleErrorResponse(res, err) + } + workspaceTemplate.GitProviderConfigId = &gitProviderConfigId + } + + return &workspaceTemplate, nil +} + +func processCmdArgument(argument string, apiClient *apiclient.APIClient, ctx context.Context) (*string, error) { + if *workspaceConfigurationFlags.Builder != "" && *workspaceConfigurationFlags.Builder != views_util.DEVCONTAINER && *workspaceConfigurationFlags.DevcontainerPath != "" { + return nil, fmt.Errorf("can't set devcontainer file path if builder is not set to %s", views_util.DEVCONTAINER) + } + + apiServerConfig, res, err := apiClient.ServerAPI.GetConfig(context.Background()).Execute() + if err != nil { + return nil, apiclient_util.HandleErrorResponse(res, err) + } + + existingWorkspaceTemplateNames, err := getExistingWorkspaceTemplateNames(apiClient) + if err != nil { + return nil, err + } + + repoUrl, err := util.GetValidatedUrl(argument) + if err != nil { + return nil, err + } + + _, res, err = apiClient.GitProviderAPI.GetGitContext(ctx).Repository(apiclient.GetRepositoryContext{ + Url: repoUrl, + }).Execute() + if err != nil { + return nil, apiclient_util.HandleErrorResponse(res, err) + } + + workspaceConfigurationFlags.GitProviderConfig, err = create_cmd.GetGitProviderConfigIdFromFlag(ctx, apiClient, workspaceConfigurationFlags.GitProviderConfig) + if err != nil { + return nil, err + } + + workspace, err := create_cmd.GetCreateWorkspaceDtoFromFlags(workspaceConfigurationFlags) + if err != nil { + return nil, err + } + + var name string + if nameFlag != "" { + name = nameFlag + } else { + workspaceName := create_cmd.GetWorkspaceNameFromRepo(repoUrl) + name = create_cmd.GetSuggestedName(workspaceName, existingWorkspaceTemplateNames) + } + + if workspace.GitProviderConfigId == nil || *workspace.GitProviderConfigId == "" { + gitProviderConfigId, res, err := apiClient.GitProviderAPI.FindGitProviderIdForUrl(ctx, url.QueryEscape(repoUrl)).Execute() + if err != nil { + return nil, apiclient_util.HandleErrorResponse(res, err) + } + *workspace.GitProviderConfigId = gitProviderConfigId + } + + newWorkspaceTemplate := apiclient.CreateWorkspaceTemplateDTO{ + Name: name, + BuildConfig: workspace.BuildConfig, + Image: workspace.Image, + User: workspace.User, + RepositoryUrl: repoUrl, + EnvVars: workspace.EnvVars, + GitProviderConfigId: workspace.GitProviderConfigId, + } + + if newWorkspaceTemplate.Image == nil { + newWorkspaceTemplate.Image = &apiServerConfig.DefaultWorkspaceImage + } + + if newWorkspaceTemplate.User == nil { + newWorkspaceTemplate.User = &apiServerConfig.DefaultWorkspaceUser + } + + res, err = apiClient.WorkspaceTemplateAPI.SaveWorkspaceTemplate(ctx).WorkspaceTemplate(newWorkspaceTemplate).Execute() + if err != nil { + return nil, apiclient_util.HandleErrorResponse(res, err) + } + + return &newWorkspaceTemplate.Name, nil +} + +func getExistingWorkspaceTemplateNames(apiClient *apiclient.APIClient) ([]string, error) { + var existingWorkspaceTemplateNames []string + + existingWorkspaceTemplates, res, err := apiClient.WorkspaceTemplateAPI.ListWorkspaceTemplates(context.Background()).Execute() + if err != nil { + return nil, apiclient_util.HandleErrorResponse(res, err) + } + + for _, wt := range existingWorkspaceTemplates { + existingWorkspaceTemplateNames = append(existingWorkspaceTemplateNames, wt.Name) + } + + return existingWorkspaceTemplateNames, nil +} + +var nameFlag string + +var workspaceConfigurationFlags = cmd_common.WorkspaceConfigurationFlags{ + Builder: new(views_util.BuildChoice), + CustomImage: new(string), + CustomImageUser: new(string), + Branches: new([]string), + DevcontainerPath: new(string), + EnvVars: new([]string), + Manual: new(bool), + GitProviderConfig: new(string), + Labels: new([]string), +} + +func init() { + createCmd.Flags().StringVar(&nameFlag, "name", "", "Specify the workspace template name") + cmd_common.AddWorkspaceConfigurationFlags(createCmd, workspaceConfigurationFlags, false) +} diff --git a/pkg/cmd/workspacetemplate/delete.go b/pkg/cmd/workspacetemplate/delete.go new file mode 100644 index 0000000000..d68a1c89f7 --- /dev/null +++ b/pkg/cmd/workspacetemplate/delete.go @@ -0,0 +1,117 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package workspacetemplate + +import ( + "context" + "fmt" + + "github.com/charmbracelet/huh" + apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" + "github.com/daytonaio/daytona/pkg/apiclient" + cmd_common "github.com/daytonaio/daytona/pkg/cmd/common" + "github.com/daytonaio/daytona/pkg/views" + "github.com/daytonaio/daytona/pkg/views/selection" + views_util "github.com/daytonaio/daytona/pkg/views/util" + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" +) + +var allFlag bool +var yesFlag bool +var forceFlag bool + +var deleteCmd = &cobra.Command{ + Use: "delete", + Short: "Delete a workspace template", + Args: cobra.MaximumNArgs(1), + Aliases: cmd_common.GetAliases("delete"), + RunE: func(cmd *cobra.Command, args []string) error { + var selectedWorkspaceTemplate *apiclient.WorkspaceTemplate + var selectedWorkspaceTemplateName string + + apiClient, err := apiclient_util.GetApiClient(nil) + if err != nil { + return err + } + + if allFlag { + if !yesFlag { + form := huh.NewForm( + huh.NewGroup( + huh.NewConfirm(). + Title("Delete all workspace templates?"). + Description("Are you sure you want to delete all workspace templates?"). + Value(&yesFlag), + ), + ).WithTheme(views.GetCustomTheme()) + + err := form.Run() + if err != nil { + return err + } + + if !yesFlag { + fmt.Println("Operation canceled.") + return nil + } + } + + workspaceTemplates, res, err := apiClient.WorkspaceTemplateAPI.ListWorkspaceTemplates(context.Background()).Execute() + if err != nil { + return apiclient_util.HandleErrorResponse(res, err) + } + + if len(workspaceTemplates) == 0 { + views_util.NotifyEmptyWorkspaceTemplateList(false) + return nil + } + + for _, workspaceTemplate := range workspaceTemplates { + selectedWorkspaceTemplateName = workspaceTemplate.Name + res, err := apiClient.WorkspaceTemplateAPI.DeleteWorkspaceTemplate(context.Background(), selectedWorkspaceTemplateName).Execute() + if err != nil { + log.Error(apiclient_util.HandleErrorResponse(res, err)) + continue + } + views.RenderInfoMessage("Deleted workspace template: " + selectedWorkspaceTemplateName) + } + return nil + } + + if len(args) == 0 { + workspaceTemplates, res, err := apiClient.WorkspaceTemplateAPI.ListWorkspaceTemplates(context.Background()).Execute() + if err != nil { + return apiclient_util.HandleErrorResponse(res, err) + } + + if len(workspaceTemplates) == 0 { + views.RenderInfoMessage("No workspace templates found") + return nil + } + + selectedWorkspaceTemplate = selection.GetWorkspaceTemplateFromPrompt(workspaceTemplates, 0, false, false, "Delete") + if selectedWorkspaceTemplate == nil { + return nil + } + selectedWorkspaceTemplateName = selectedWorkspaceTemplate.Name + } else { + selectedWorkspaceTemplateName = args[0] + } + + res, err := apiClient.WorkspaceTemplateAPI.DeleteWorkspaceTemplate(context.Background(), selectedWorkspaceTemplateName).Force(forceFlag).Execute() + if err != nil { + return apiclient_util.HandleErrorResponse(res, err) + } + + views.RenderInfoMessage("Workspace template deleted successfully") + return nil + }, +} + +func init() { + deleteCmd.Flags().BoolVarP(&allFlag, "all", "a", false, "Delete all workspace templates") + deleteCmd.Flags().BoolVarP(&yesFlag, "yes", "y", false, "Confirm deletion without prompt") + deleteCmd.Flags().BoolVarP(&forceFlag, "force", "f", false, "Force delete prebuild") +} diff --git a/pkg/cmd/workspacetemplate/export.go b/pkg/cmd/workspacetemplate/export.go new file mode 100644 index 0000000000..4392432267 --- /dev/null +++ b/pkg/cmd/workspacetemplate/export.go @@ -0,0 +1,132 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package workspacetemplate + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + + "github.com/atotto/clipboard" + apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" + "github.com/daytonaio/daytona/pkg/apiclient" + "github.com/daytonaio/daytona/pkg/cmd/format" + "github.com/daytonaio/daytona/pkg/views" + "github.com/daytonaio/daytona/pkg/views/selection" + views_util "github.com/daytonaio/daytona/pkg/views/util" + "github.com/spf13/cobra" +) + +var exportCmd = &cobra.Command{ + Use: "export", + Short: "Export a workspace template", + Args: cobra.MaximumNArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + var selectedWorkspaceTemplate *apiclient.WorkspaceTemplate + ctx := context.Background() + + apiClient, err := apiclient_util.GetApiClient(nil) + if err != nil { + return err + } + + if allFlag { + templates, res, err := apiClient.WorkspaceTemplateAPI.ListWorkspaceTemplates(ctx).Execute() + if err != nil { + return apiclient_util.HandleErrorResponse(res, err) + } + + if len(templates) == 0 { + views_util.NotifyEmptyWorkspaceTemplateList(true) + return nil + } + + return exportWorkspaceTemplates(templates) + } + + if len(args) == 0 { + templates, res, err := apiClient.WorkspaceTemplateAPI.ListWorkspaceTemplates(ctx).Execute() + if err != nil { + return apiclient_util.HandleErrorResponse(res, err) + } + + if len(templates) == 0 { + views_util.NotifyEmptyWorkspaceTemplateList(true) + return nil + } + + if format.FormatFlag != "" { + format.UnblockStdOut() + } + + selectedWorkspaceTemplate = selection.GetWorkspaceTemplateFromPrompt(templates, 0, false, false, "Export") + if selectedWorkspaceTemplate == nil { + return nil + } + + if format.FormatFlag != "" { + format.BlockStdOut() + } + } else { + var res *http.Response + selectedWorkspaceTemplate, res, err = apiClient.WorkspaceTemplateAPI.FindWorkspaceTemplate(ctx, args[0]).Execute() + if err != nil { + return apiclient_util.HandleErrorResponse(res, err) + } + } + + return exportWorkspaceTemplates([]apiclient.WorkspaceTemplate{*selectedWorkspaceTemplate}) + }, +} + +func init() { + exportCmd.Flags().BoolVarP(&allFlag, "all", "a", false, "Export all workspace templates") + format.RegisterFormatFlag(exportCmd) +} + +func exportWorkspaceTemplates(templates []apiclient.WorkspaceTemplate) error { + if len(templates) == 0 { + return nil + } + + var pbFlag bool + + for i := range templates { + templates[i].GitProviderConfigId = nil + if templates[i].Prebuilds != nil { + templates[i].Prebuilds = nil + pbFlag = true + } + } + + data, err := json.MarshalIndent(templates, "", " ") + if pbFlag { + views.RenderContainerLayout("Prebuilds have been removed from the export.") + } + if err != nil { + return err + } + + if format.FormatFlag != "" { + if len(templates) == 1 { + formattedData := format.NewFormatter(templates[0]) + formattedData.Print() + } else { + formattedData := format.NewFormatter(templates) + formattedData.Print() + } + return nil + } + + fmt.Println(string(data)) + + if err := clipboard.WriteAll(string(data)); err == nil { + views.RenderContainerLayout(views.GetInfoMessage("The export has been copied to your clipboard.")) + } else { + views.RenderContainerLayout(views.GetInfoMessage("Could not copy the export to your clipboard.")) + } + + return nil +} diff --git a/pkg/cmd/workspacetemplate/import.go b/pkg/cmd/workspacetemplate/import.go new file mode 100644 index 0000000000..17243c042c --- /dev/null +++ b/pkg/cmd/workspacetemplate/import.go @@ -0,0 +1,242 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package workspacetemplate + +import ( + "context" + "encoding/json" + "fmt" + "io" + "net/url" + "os" + + "github.com/charmbracelet/huh" + "github.com/daytonaio/daytona/internal/util" + apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" + "github.com/daytonaio/daytona/pkg/apiclient" + "github.com/daytonaio/daytona/pkg/views" + "github.com/daytonaio/daytona/pkg/views/selection" + views_util "github.com/daytonaio/daytona/pkg/views/util" + "github.com/daytonaio/daytona/pkg/views/workspace/create" + "github.com/spf13/cobra" +) + +var filePath string + +var importCmd = &cobra.Command{ + Use: "import", + Short: "Import a workspace template from a JSON object", + Args: cobra.MaximumNArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + var inputText string + ctx := context.Background() + + apiClient, err := apiclient_util.GetApiClient(nil) + if err != nil { + return err + } + + workspaceTemplateList, res, err := apiClient.WorkspaceTemplateAPI.ListWorkspaceTemplates(ctx).Execute() + if err != nil { + return apiclient_util.HandleErrorResponse(res, err) + } + + if filePath != "" { + if filePath == "-" { + inputBytes, err := io.ReadAll(os.Stdin) + if err != nil { + return fmt.Errorf("error reading stdin: %v", err) + } + inputText = string(inputBytes) + } else { + inputBytes, err := os.ReadFile(filePath) + if err != nil { + return fmt.Errorf("error reading file: %v", err) + } + inputText = string(inputBytes) + } + + } else { + form := huh.NewForm( + huh.NewGroup( + huh.NewText(). + Title("Import Workspace Template"). + Description("Enter Workspace Template as a JSON object or an array of JSON objects"). + CharLimit(-1). + Value(&inputText), + ), + ).WithTheme(views.GetCustomTheme()).WithHeight(20) + err = form.Run() + if err != nil { + return err + } + } + + var template apiclient.WorkspaceTemplate + err = json.Unmarshal([]byte(inputText), &template) + if err == nil { + err = importWorkspaceTemplate(ctx, apiClient, template, &workspaceTemplateList) + if err != nil { + return fmt.Errorf("error importing workspace template: %v", err) + } + } else { + var templates []apiclient.WorkspaceTemplate + err = json.Unmarshal([]byte(inputText), &templates) + if err != nil { + return fmt.Errorf("invalid JSON input: %v", err) + } + + for _, t := range templates { + err = importWorkspaceTemplate(ctx, apiClient, t, &workspaceTemplateList) + if err != nil { + return fmt.Errorf("error importing workspace template: %v", err) + } + } + } + return nil + }, +} + +func init() { + importCmd.Flags().StringVarP(&filePath, "file", "f", "", "Import workspace template from a JSON file. Use '-' to read from stdin.") +} + +func checkWorkspaceTemplateAlreadyExists(templateName string, workspaceTemplateList *[]apiclient.WorkspaceTemplate) bool { + for _, t := range *workspaceTemplateList { + if t.Name == templateName { + return true + } + } + return false +} + +func importWorkspaceTemplate(ctx context.Context, apiClient *apiclient.APIClient, template apiclient.WorkspaceTemplate, workspaceTemplateList *[]apiclient.WorkspaceTemplate) error { + if checkWorkspaceTemplateAlreadyExists(template.Name, workspaceTemplateList) { + return fmt.Errorf("workspace template already present with name \"%s\"", template.Name) + } + + var verifiedGitProvider bool + if template.GitProviderConfigId != nil { + _, _, err := apiClient.GitProviderAPI.FindGitProvider(ctx, *template.GitProviderConfigId).Execute() + if err == nil { + verifiedGitProvider = true + } + } + + var gitProviders []apiclient.GitProvider + + if !verifiedGitProvider { + var err error + gitProviders, _, err = apiClient.GitProviderAPI.ListGitProvidersForUrl(ctx, url.QueryEscape(template.RepositoryUrl)).Execute() + if err != nil { + return fmt.Errorf("error fetching Git providers: %v", err) + } + + if len(gitProviders) == 0 { + gitProviderConfigId, _, err := apiClient.GitProviderAPI.FindGitProviderIdForUrl(ctx, url.QueryEscape(template.RepositoryUrl)).Execute() + if err != nil { + return fmt.Errorf("error fetching Git provider: %v", err) + } + template.GitProviderConfigId = &gitProviderConfigId + } + + if len(gitProviders) == 1 && template.GitProviderConfigId == nil { + template.GitProviderConfigId = &gitProviders[0].Id + } else if len(gitProviders) > 1 && template.GitProviderConfigId == nil { + selectedGitProvider := selection.GetGitProviderConfigFromPrompt(selection.GetGitProviderConfigParams{ + GitProviderConfigs: gitProviders, + ActionVerb: "Use", + }) + template.GitProviderConfigId = &selectedGitProvider.Id + } + } + + apiServerConfig, res, err := apiClient.ServerAPI.GetConfig(context.Background()).Execute() + if err != nil { + return apiclient_util.HandleErrorResponse(res, err) + } + + newWorkspaceTemplate := apiclient.CreateWorkspaceTemplateDTO{ + Name: template.Name, + BuildConfig: template.BuildConfig, + Image: &template.Image, + User: &template.User, + RepositoryUrl: template.RepositoryUrl, + EnvVars: template.EnvVars, + GitProviderConfigId: template.GitProviderConfigId, + } + + if newWorkspaceTemplate.Image == nil { + newWorkspaceTemplate.Image = &apiServerConfig.DefaultWorkspaceImage + } + + if newWorkspaceTemplate.User == nil { + newWorkspaceTemplate.User = &apiServerConfig.DefaultWorkspaceUser + } + + existingWorkspaceTemplateNames, err := getExistingWorkspaceTemplateNames(apiClient) + if err != nil { + return err + } + + apiServerConfig, res, err = apiClient.ServerAPI.GetConfig(context.Background()).Execute() + if err != nil { + return apiclient_util.HandleErrorResponse(res, err) + } + + workspaceDefaults := &views_util.WorkspaceTemplateDefaults{ + BuildChoice: views_util.AUTOMATIC, + Image: &apiServerConfig.DefaultWorkspaceImage, + ImageUser: &apiServerConfig.DefaultWorkspaceUser, + DevcontainerFilePath: create.DEVCONTAINER_FILEPATH, + } + + createDto := []apiclient.CreateWorkspaceDTO{ + { + Name: template.Name, + Source: apiclient.CreateWorkspaceSourceDTO{ + Repository: apiclient.GitRepository{ + Url: template.RepositoryUrl, + }, + }, + BuildConfig: template.BuildConfig, + EnvVars: template.EnvVars, + GitProviderConfigId: template.GitProviderConfigId, + }, + } + + create.WorkspacesConfigurationChanged, err = create.RunWorkspaceConfiguration(&createDto, *workspaceDefaults, true) + if err != nil { + return err + } + + submissionFormConfig := create.SubmissionFormParams{ + ChosenName: &template.Name, + SuggestedName: template.Name, + ExistingWorkspaceNames: existingWorkspaceTemplateNames, + WorkspaceList: &createDto, + NameLabel: "Workspace template", + Defaults: workspaceDefaults, + ImportConfirmation: util.Pointer(true), + } + + err = create.RunSubmissionForm(submissionFormConfig) + if err != nil { + return err + } + + if submissionFormConfig.ImportConfirmation != nil && *submissionFormConfig.ImportConfirmation { + res, err = apiClient.WorkspaceTemplateAPI.SaveWorkspaceTemplate(ctx).WorkspaceTemplate(newWorkspaceTemplate).Execute() + if err != nil { + return apiclient_util.HandleErrorResponse(res, err) + } + + *workspaceTemplateList = append(*workspaceTemplateList, template) + views.RenderInfoMessage(fmt.Sprintf("Workspace template %s imported successfully", newWorkspaceTemplate.Name)) + return nil + } + + views.RenderInfoMessage(fmt.Sprintf("Workspace template %s import cancelled", newWorkspaceTemplate.Name)) + return nil +} diff --git a/pkg/cmd/projectconfig/info.go b/pkg/cmd/workspacetemplate/info.go similarity index 56% rename from pkg/cmd/projectconfig/info.go rename to pkg/cmd/workspacetemplate/info.go index 482e4eb955..b1aa9ee6b0 100644 --- a/pkg/cmd/projectconfig/info.go +++ b/pkg/cmd/workspacetemplate/info.go @@ -1,7 +1,7 @@ // Copyright 2024 Daytona Platforms Inc. // SPDX-License-Identifier: Apache-2.0 -package projectconfig +package workspacetemplate import ( "context" @@ -9,17 +9,18 @@ import ( apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" "github.com/daytonaio/daytona/pkg/apiclient" + cmd_common "github.com/daytonaio/daytona/pkg/cmd/common" "github.com/daytonaio/daytona/pkg/cmd/format" - "github.com/daytonaio/daytona/pkg/views/projectconfig/info" + "github.com/daytonaio/daytona/pkg/views/selection" views_util "github.com/daytonaio/daytona/pkg/views/util" - "github.com/daytonaio/daytona/pkg/views/workspace/selection" + "github.com/daytonaio/daytona/pkg/views/workspacetemplate/info" "github.com/spf13/cobra" ) -var projectConfigInfoCmd = &cobra.Command{ +var infoCmd = &cobra.Command{ Use: "info", - Short: "Show project config info", - Aliases: []string{"view", "inspect"}, + Short: "Show workspace template info", + Aliases: cmd_common.GetAliases("info"), Args: cobra.MaximumNArgs(1), RunE: func(cmd *cobra.Command, args []string) error { ctx := context.Background() @@ -34,16 +35,16 @@ var projectConfigInfoCmd = &cobra.Command{ return apiclient_util.HandleErrorResponse(res, err) } - var projectConfig *apiclient.ProjectConfig + var workspaceTemplate *apiclient.WorkspaceTemplate if len(args) == 0 { - projectConfigList, res, err := apiClient.ProjectConfigAPI.ListProjectConfigs(ctx).Execute() + workspaceTemplateList, res, err := apiClient.WorkspaceTemplateAPI.ListWorkspaceTemplates(ctx).Execute() if err != nil { return apiclient_util.HandleErrorResponse(res, err) } - if len(projectConfigList) == 0 { - views_util.NotifyEmptyProjectConfigList(true) + if len(workspaceTemplateList) == 0 { + views_util.NotifyEmptyWorkspaceTemplateList(true) return nil } @@ -51,34 +52,34 @@ var projectConfigInfoCmd = &cobra.Command{ format.UnblockStdOut() } - projectConfig = selection.GetProjectConfigFromPrompt(projectConfigList, 0, false, false, "View") + workspaceTemplate = selection.GetWorkspaceTemplateFromPrompt(workspaceTemplateList, 0, false, false, "View") if format.FormatFlag != "" { format.BlockStdOut() } } else { var res *http.Response - projectConfig, res, err = apiClient.ProjectConfigAPI.GetProjectConfig(ctx, args[0]).Execute() + workspaceTemplate, res, err = apiClient.WorkspaceTemplateAPI.FindWorkspaceTemplate(ctx, args[0]).Execute() if err != nil { return apiclient_util.HandleErrorResponse(res, err) } } - if projectConfig == nil { + if workspaceTemplate == nil { return nil } if format.FormatFlag != "" { - formattedData := format.NewFormatter(projectConfig) + formattedData := format.NewFormatter(workspaceTemplate) formattedData.Print() return nil } - info.Render(projectConfig, apiServerConfig, false) + info.Render(workspaceTemplate, apiServerConfig, false) return nil }, } func init() { - format.RegisterFormatFlag(projectConfigInfoCmd) + format.RegisterFormatFlag(infoCmd) } diff --git a/pkg/cmd/projectconfig/list.go b/pkg/cmd/workspacetemplate/list.go similarity index 64% rename from pkg/cmd/projectconfig/list.go rename to pkg/cmd/workspacetemplate/list.go index 34aec285c3..9ce0304167 100644 --- a/pkg/cmd/projectconfig/list.go +++ b/pkg/cmd/workspacetemplate/list.go @@ -1,22 +1,23 @@ // Copyright 2024 Daytona Platforms Inc. // SPDX-License-Identifier: Apache-2.0 -package projectconfig +package workspacetemplate import ( "context" apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" + cmd_common "github.com/daytonaio/daytona/pkg/cmd/common" "github.com/daytonaio/daytona/pkg/cmd/format" - projectconfig_view "github.com/daytonaio/daytona/pkg/views/projectconfig/list" + workspacetemplate_view "github.com/daytonaio/daytona/pkg/views/workspacetemplate/list" "github.com/spf13/cobra" ) -var projectConfigListCmd = &cobra.Command{ +var listCmd = &cobra.Command{ Use: "list", - Short: "Lists project configs", - Aliases: []string{"ls"}, + Short: "Lists workspace templates", Args: cobra.NoArgs, + Aliases: cmd_common.GetAliases("list"), RunE: func(cmd *cobra.Command, args []string) error { ctx := context.Background() var specifyGitProviders bool @@ -40,22 +41,22 @@ var projectConfigListCmd = &cobra.Command{ return apiclient_util.HandleErrorResponse(res, err) } - projectConfigs, res, err := apiClient.ProjectConfigAPI.ListProjectConfigs(context.Background()).Execute() + workspaceTemplates, res, err := apiClient.WorkspaceTemplateAPI.ListWorkspaceTemplates(context.Background()).Execute() if err != nil { return apiclient_util.HandleErrorResponse(res, err) } if format.FormatFlag != "" { - formattedData := format.NewFormatter(projectConfigs) + formattedData := format.NewFormatter(workspaceTemplates) formattedData.Print() return nil } - projectconfig_view.ListProjectConfigs(projectConfigs, apiServerConfig, specifyGitProviders) + workspacetemplate_view.ListWorkspaceTemplates(workspaceTemplates, apiServerConfig, specifyGitProviders) return nil }, } func init() { - format.RegisterFormatFlag(projectConfigListCmd) + format.RegisterFormatFlag(listCmd) } diff --git a/pkg/cmd/workspacetemplate/setdefault.go b/pkg/cmd/workspacetemplate/setdefault.go new file mode 100644 index 0000000000..882bcb568b --- /dev/null +++ b/pkg/cmd/workspacetemplate/setdefault.go @@ -0,0 +1,63 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package workspacetemplate + +import ( + "context" + "fmt" + + apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" + cmd_common "github.com/daytonaio/daytona/pkg/cmd/common" + "github.com/daytonaio/daytona/pkg/views" + "github.com/daytonaio/daytona/pkg/views/selection" + views_util "github.com/daytonaio/daytona/pkg/views/util" + "github.com/spf13/cobra" +) + +var setDefaultCmd = &cobra.Command{ + Use: "set-default", + Short: "Set workspace template info", + Args: cobra.MaximumNArgs(1), + Aliases: cmd_common.GetAliases("set-default"), + RunE: func(cmd *cobra.Command, args []string) error { + var workspaceTemplateName string + ctx := context.Background() + + apiClient, err := apiclient_util.GetApiClient(nil) + if err != nil { + return err + } + + if len(args) == 0 { + workspaceTemplateList, res, err := apiClient.WorkspaceTemplateAPI.ListWorkspaceTemplates(ctx).Execute() + if err != nil { + return apiclient_util.HandleErrorResponse(res, err) + } + + if len(workspaceTemplateList) == 0 { + views_util.NotifyEmptyWorkspaceTemplateList(true) + return nil + } + + workspaceTemplate := selection.GetWorkspaceTemplateFromPrompt(workspaceTemplateList, 0, false, false, "Make Default") + if workspaceTemplate == nil { + return nil + } + workspaceTemplateName = workspaceTemplate.Name + } else { + workspaceTemplateName = args[0] + } + + res, err := apiClient.WorkspaceTemplateAPI.SetDefaultWorkspaceTemplate(ctx, workspaceTemplateName).Execute() + if err != nil { + return apiclient_util.HandleErrorResponse(res, err) + } + + views.RenderInfoMessage(fmt.Sprintf("Workspace template '%s' set as default", workspaceTemplateName)) + return nil + }, +} + +func init() { +} diff --git a/pkg/cmd/projectconfig/update.go b/pkg/cmd/workspacetemplate/update.go similarity index 50% rename from pkg/cmd/projectconfig/update.go rename to pkg/cmd/workspacetemplate/update.go index ff86465609..25fb6eaf87 100644 --- a/pkg/cmd/projectconfig/update.go +++ b/pkg/cmd/workspacetemplate/update.go @@ -1,7 +1,7 @@ // Copyright 2024 Daytona Platforms Inc. // SPDX-License-Identifier: Apache-2.0 -package projectconfig +package workspacetemplate import ( "context" @@ -10,19 +10,21 @@ import ( apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" "github.com/daytonaio/daytona/pkg/apiclient" + cmd_common "github.com/daytonaio/daytona/pkg/cmd/common" "github.com/daytonaio/daytona/pkg/views" + "github.com/daytonaio/daytona/pkg/views/selection" views_util "github.com/daytonaio/daytona/pkg/views/util" "github.com/daytonaio/daytona/pkg/views/workspace/create" - "github.com/daytonaio/daytona/pkg/views/workspace/selection" "github.com/spf13/cobra" ) -var projectConfigUpdateCmd = &cobra.Command{ - Use: "update", - Short: "Update a project config", - Args: cobra.MaximumNArgs(1), +var updateCmd = &cobra.Command{ + Use: "update", + Short: "Update a workspace template", + Args: cobra.MaximumNArgs(1), + Aliases: cmd_common.GetAliases("update"), RunE: func(cmd *cobra.Command, args []string) error { - var projectConfig *apiclient.ProjectConfig + var workspaceTemplate *apiclient.WorkspaceTemplate var res *http.Response ctx := context.Background() @@ -32,61 +34,61 @@ var projectConfigUpdateCmd = &cobra.Command{ } if len(args) == 0 { - projectConfigList, res, err := apiClient.ProjectConfigAPI.ListProjectConfigs(ctx).Execute() + workspaceTemplateList, res, err := apiClient.WorkspaceTemplateAPI.ListWorkspaceTemplates(ctx).Execute() if err != nil { return apiclient_util.HandleErrorResponse(res, err) } - if len(projectConfigList) == 0 { - views_util.NotifyEmptyProjectConfigList(true) + if len(workspaceTemplateList) == 0 { + views_util.NotifyEmptyWorkspaceTemplateList(true) return nil } - projectConfig = selection.GetProjectConfigFromPrompt(projectConfigList, 0, false, false, "Update") - if projectConfig == nil { + workspaceTemplate = selection.GetWorkspaceTemplateFromPrompt(workspaceTemplateList, 0, false, false, "Update") + if workspaceTemplate == nil { return nil } } else { - projectConfig, res, err = apiClient.ProjectConfigAPI.GetProjectConfig(ctx, args[0]).Execute() + workspaceTemplate, res, err = apiClient.WorkspaceTemplateAPI.FindWorkspaceTemplate(ctx, args[0]).Execute() if err != nil { return apiclient_util.HandleErrorResponse(res, err) } } - if projectConfig == nil { + if workspaceTemplate == nil { return nil } - createDto := []apiclient.CreateProjectDTO{ + createDto := []apiclient.CreateWorkspaceDTO{ { - Name: projectConfig.Name, - Source: apiclient.CreateProjectSourceDTO{ + Name: workspaceTemplate.Name, + Source: apiclient.CreateWorkspaceSourceDTO{ Repository: apiclient.GitRepository{ - Url: projectConfig.RepositoryUrl, + Url: workspaceTemplate.RepositoryUrl, }, }, - BuildConfig: projectConfig.BuildConfig, - EnvVars: projectConfig.EnvVars, - GitProviderConfigId: projectConfig.GitProviderConfigId, + BuildConfig: workspaceTemplate.BuildConfig, + EnvVars: workspaceTemplate.EnvVars, + GitProviderConfigId: workspaceTemplate.GitProviderConfigId, }, } - projectDefaults := &views_util.ProjectConfigDefaults{ + workspaceDefaults := &views_util.WorkspaceTemplateDefaults{ BuildChoice: views_util.AUTOMATIC, - Image: &projectConfig.Image, - ImageUser: &projectConfig.User, + Image: &workspaceTemplate.Image, + ImageUser: &workspaceTemplate.User, } - if projectConfig.BuildConfig != nil && projectConfig.BuildConfig.Devcontainer != nil { - projectDefaults.DevcontainerFilePath = projectConfig.BuildConfig.Devcontainer.FilePath + if workspaceTemplate.BuildConfig != nil && workspaceTemplate.BuildConfig.Devcontainer != nil { + workspaceDefaults.DevcontainerFilePath = workspaceTemplate.BuildConfig.Devcontainer.FilePath } - _, err = create.RunProjectConfiguration(&createDto, *projectDefaults, false) + _, err = create.RunWorkspaceConfiguration(&createDto, *workspaceDefaults, false) if err != nil { return err } - eligibleGitProviders, res, err := apiClient.GitProviderAPI.ListGitProvidersForUrl(ctx, url.QueryEscape(projectConfig.RepositoryUrl)).Execute() + eligibleGitProviders, res, err := apiClient.GitProviderAPI.ListGitProvidersForUrl(ctx, url.QueryEscape(workspaceTemplate.RepositoryUrl)).Execute() if err != nil { return apiclient_util.HandleErrorResponse(res, err) } @@ -96,7 +98,7 @@ var projectConfigUpdateCmd = &cobra.Command{ GitProviderConfigs: eligibleGitProviders, ActionVerb: "Use", WithNoneOption: true, - PreselectedGitProviderId: projectConfig.GitProviderConfigId, + PreselectedGitProviderId: workspaceTemplate.GitProviderConfigId, }) if selectedGitProvider == nil { @@ -110,8 +112,8 @@ var projectConfigUpdateCmd = &cobra.Command{ } } - newProjectConfig := apiclient.CreateProjectConfigDTO{ - Name: projectConfig.Name, + newWorkspaceTemplate := apiclient.CreateWorkspaceTemplateDTO{ + Name: workspaceTemplate.Name, BuildConfig: createDto[0].BuildConfig, Image: createDto[0].Image, User: createDto[0].User, @@ -120,12 +122,12 @@ var projectConfigUpdateCmd = &cobra.Command{ GitProviderConfigId: createDto[0].GitProviderConfigId, } - res, err = apiClient.ProjectConfigAPI.SetProjectConfig(ctx).ProjectConfig(newProjectConfig).Execute() + res, err = apiClient.WorkspaceTemplateAPI.SaveWorkspaceTemplate(ctx).WorkspaceTemplate(newWorkspaceTemplate).Execute() if err != nil { return apiclient_util.HandleErrorResponse(res, err) } - views.RenderInfoMessage("Project config updated successfully") + views.RenderInfoMessage("Workspace template updated successfully") return nil }, } diff --git a/pkg/cmd/workspacetemplate/workspacetemplate.go b/pkg/cmd/workspacetemplate/workspacetemplate.go new file mode 100644 index 0000000000..2de572803d --- /dev/null +++ b/pkg/cmd/workspacetemplate/workspacetemplate.go @@ -0,0 +1,28 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package workspacetemplate + +import ( + "github.com/daytonaio/daytona/internal/util" + "github.com/spf13/cobra" +) + +var WorkspaceTemplateCmd = &cobra.Command{ + Use: "template", + Short: "Manage workspace templates", + Args: cobra.NoArgs, + GroupID: util.TARGET_GROUP, + Aliases: []string{"templates", "workspace-template", "workspace-templates", "wt"}, +} + +func init() { + WorkspaceTemplateCmd.AddCommand(listCmd) + WorkspaceTemplateCmd.AddCommand(infoCmd) + WorkspaceTemplateCmd.AddCommand(createCmd) + WorkspaceTemplateCmd.AddCommand(updateCmd) + WorkspaceTemplateCmd.AddCommand(setDefaultCmd) + WorkspaceTemplateCmd.AddCommand(deleteCmd) + WorkspaceTemplateCmd.AddCommand(exportCmd) + WorkspaceTemplateCmd.AddCommand(importCmd) +} diff --git a/internal/workspace_mode.go b/pkg/common/agent_mode.go similarity index 62% rename from internal/workspace_mode.go rename to pkg/common/agent_mode.go index 0e648b25e3..11a5fc4bfe 100644 --- a/internal/workspace_mode.go +++ b/pkg/common/agent_mode.go @@ -1,17 +1,17 @@ // Copyright 2024 Daytona Platforms Inc. // SPDX-License-Identifier: Apache-2.0 -package internal +package common import "os" -func WorkspaceMode() bool { +func AgentMode() bool { _, devEnv := os.LookupEnv("DAYTONA_DEV") if devEnv { return false } - val, wsMode := os.LookupEnv("DAYTONA_WS_ID") - if wsMode && val != "" { + val, agentMode := os.LookupEnv("DAYTONA_TARGET_ID") + if agentMode && val != "" { return true } return false diff --git a/pkg/common/env.go b/pkg/common/env.go new file mode 100644 index 0000000000..f58795739d --- /dev/null +++ b/pkg/common/env.go @@ -0,0 +1,54 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package common + +import ( + "strings" + + "github.com/daytonaio/daytona/pkg/models" +) + +const ( + ContainerRegistryServerEnvVarSuffix = "_CONTAINER_REGISTRY_SERVER" + ContainerRegistryUsernameEnvVarSuffix = "_CONTAINER_REGISTRY_USERNAME" + ContainerRegistryPasswordEnvVarSuffix = "_CONTAINER_REGISTRY_PASSWORD" +) + +type ContainerRegistries map[string]*models.ContainerRegistry + +func (c ContainerRegistries) FindContainerRegistryByImageName(image string) *models.ContainerRegistry { + parts := strings.Split(image, "/") + + if len(parts) < 3 { + return c["docker.io"] + } + + return c[parts[0]] +} + +func ExtractContainerRegistryFromEnvVars(envVars map[string]string) (map[string]string, ContainerRegistries) { + resultEnvVars := make(map[string]string) + containerRegistryEnvVars := make(map[string]*models.ContainerRegistry) + + for k, v := range envVars { + if !isContainerRegistryEnvVar(k) { + resultEnvVars[k] = v + } else if strings.HasSuffix(k, ContainerRegistryServerEnvVarSuffix) { + usernameKey := strings.ReplaceAll(k, ContainerRegistryServerEnvVarSuffix, ContainerRegistryUsernameEnvVarSuffix) + passwordKey := strings.ReplaceAll(k, ContainerRegistryServerEnvVarSuffix, ContainerRegistryPasswordEnvVarSuffix) + + containerRegistryEnvVars[v] = &models.ContainerRegistry{ + Server: v, + Username: envVars[usernameKey], + Password: envVars[passwordKey], + } + } + } + + return resultEnvVars, containerRegistryEnvVars +} + +func isContainerRegistryEnvVar(key string) bool { + return strings.HasSuffix(key, ContainerRegistryServerEnvVarSuffix) || strings.HasSuffix(key, ContainerRegistryUsernameEnvVarSuffix) || strings.HasSuffix(key, ContainerRegistryPasswordEnvVarSuffix) +} diff --git a/pkg/common/get_daytona_script.go b/pkg/common/get_daytona_script.go index b42c02b73d..7baaad64bd 100644 --- a/pkg/common/get_daytona_script.go +++ b/pkg/common/get_daytona_script.go @@ -34,7 +34,7 @@ try_download() { curl -fsSL "$url" -H "Authorization: Bearer $DAYTONA_SERVER_API_KEY" -o "$temp_file" && return 0 exit_code=$? else - echo "error: Make sure curl or wget is available in the project container" + echo "error: Make sure curl or wget is available in the workspace container" exit 127 fi >&2 echo "error: Daytona binary download failed. Exit Code: ${exit_code}" diff --git a/pkg/common/local_docker_target_config.go b/pkg/common/local_docker_target_config.go new file mode 100644 index 0000000000..3f03e24708 --- /dev/null +++ b/pkg/common/local_docker_target_config.go @@ -0,0 +1,16 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package common + +import ( + "strings" +) + +func IsLocalDockerTarget(providerName, options, runnerId string) bool { + if providerName != "docker-provider" { + return false + } + + return !strings.Contains(options, "Remote Hostname") && runnerId == LOCAL_RUNNER_ID +} diff --git a/pkg/common/local_runner.go b/pkg/common/local_runner.go new file mode 100644 index 0000000000..5acd6e3d60 --- /dev/null +++ b/pkg/common/local_runner.go @@ -0,0 +1,6 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package common + +const LOCAL_RUNNER_ID = "local" diff --git a/pkg/common/tailscale_hostname.go b/pkg/common/tailscale_hostname.go new file mode 100644 index 0000000000..fd5e55e25f --- /dev/null +++ b/pkg/common/tailscale_hostname.go @@ -0,0 +1,22 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package common + +import ( + "strings" +) + +func GetTailscaleHostname(resourceId string) string { + // Replace special chars with hyphen to form valid hostname + // String resulting in consecutive hyphens is also valid + resourceId = strings.ReplaceAll(resourceId, "_", "-") + resourceId = strings.ReplaceAll(resourceId, "*", "-") + resourceId = strings.ReplaceAll(resourceId, ".", "-") + + if len(resourceId) > 63 { + return resourceId[:63] + } + + return resourceId +} diff --git a/pkg/containerregistry/container_registry.go b/pkg/containerregistry/container_registry.go deleted file mode 100644 index 3d1227c77c..0000000000 --- a/pkg/containerregistry/container_registry.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package containerregistry - -import ( - "errors" - "strings" -) - -// ContainerRegistry represents a container registry credentials -type ContainerRegistry struct { - Server string `json:"server" validate:"required"` - Username string `json:"username" validate:"required"` - Password string `json:"password" validate:"required"` -} // @name ContainerRegistry - -func GetServerHostname(server string) (string, error) { - server = strings.TrimPrefix(server, "https://") - server = strings.TrimPrefix(server, "http://") - - parts := strings.Split(server, "/") - - if len(parts) == 0 { - return "", errors.New("invalid container registry server URL") - } - - return parts[0], nil -} diff --git a/pkg/containerregistry/store.go b/pkg/containerregistry/store.go deleted file mode 100644 index b949af8701..0000000000 --- a/pkg/containerregistry/store.go +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package containerregistry - -import "errors" - -type Store interface { - List() ([]*ContainerRegistry, error) - Find(server string) (*ContainerRegistry, error) - Save(cr *ContainerRegistry) error - Delete(cr *ContainerRegistry) error -} - -var ( - ErrContainerRegistryNotFound = errors.New("container registry not found") -) - -func IsContainerRegistryNotFound(err error) bool { - return err.Error() == ErrContainerRegistryNotFound.Error() -} diff --git a/pkg/db/api_key_store.go b/pkg/db/api_key_store.go index c97647e7d1..d224bde71b 100644 --- a/pkg/db/api_key_store.go +++ b/pkg/db/api_key_store.go @@ -4,72 +4,71 @@ package db import ( - "github.com/daytonaio/daytona/pkg/apikey" - . "github.com/daytonaio/daytona/pkg/db/dto" - "gorm.io/gorm" + "context" + + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/stores" ) type ApiKeyStore struct { - db *gorm.DB + IStore } -func NewApiKeyStore(db *gorm.DB) (*ApiKeyStore, error) { - err := db.AutoMigrate(&ApiKeyDTO{}) +func NewApiKeyStore(store IStore) (stores.ApiKeyStore, error) { + err := store.AutoMigrate(&models.ApiKey{}) if err != nil { return nil, err } - return &ApiKeyStore{db: db}, nil + return &ApiKeyStore{store}, nil } -func (a *ApiKeyStore) List() ([]*apikey.ApiKey, error) { - apiKeyDTOs := []ApiKeyDTO{} - tx := a.db.Find(&apiKeyDTOs) +func (a *ApiKeyStore) List(ctx context.Context) ([]*models.ApiKey, error) { + tx := a.GetTransaction(ctx) + + apiKeys := []*models.ApiKey{} + tx = tx.Find(&apiKeys) if tx.Error != nil { return nil, tx.Error } - apiKeys := []*apikey.ApiKey{} - for _, apiKeyDTO := range apiKeyDTOs { - apiKey := ToApiKey(apiKeyDTO) - apiKeys = append(apiKeys, &apiKey) - } return apiKeys, nil } -func (a *ApiKeyStore) Find(key string) (*apikey.ApiKey, error) { - apiKeyDTO := ApiKeyDTO{} - tx := a.db.Where("key_hash = ?", key).First(&apiKeyDTO) +func (a *ApiKeyStore) Find(ctx context.Context, key string) (*models.ApiKey, error) { + tx := a.GetTransaction(ctx) + + apiKey := &models.ApiKey{} + tx = tx.Where("key_hash = ?", key).First(apiKey) if tx.Error != nil { if IsRecordNotFound(tx.Error) { - return nil, apikey.ErrApiKeyNotFound + return nil, stores.ErrApiKeyNotFound } return nil, tx.Error } - apiKey := ToApiKey(apiKeyDTO) - - return &apiKey, nil + return apiKey, nil } -func (a *ApiKeyStore) FindByName(name string) (*apikey.ApiKey, error) { - apiKeyDTO := ApiKeyDTO{} - tx := a.db.Where("name = ?", name).First(&apiKeyDTO) +func (a *ApiKeyStore) FindByName(ctx context.Context, name string) (*models.ApiKey, error) { + tx := a.GetTransaction(ctx) + + apiKey := &models.ApiKey{} + tx = tx.Where("name = ?", name).First(apiKey) if tx.Error != nil { if IsRecordNotFound(tx.Error) { - return nil, apikey.ErrApiKeyNotFound + return nil, stores.ErrApiKeyNotFound } return nil, tx.Error } - apiKey := ToApiKey(apiKeyDTO) - - return &apiKey, nil + return apiKey, nil } -func (a *ApiKeyStore) Save(apiKey *apikey.ApiKey) error { - apiKeyDTO := ToApiKeyDTO(*apiKey) - tx := a.db.Save(&apiKeyDTO) +func (a *ApiKeyStore) Save(ctx context.Context, apiKey *models.ApiKey) error { + tx := a.GetTransaction(ctx) + + tx = tx.Save(apiKey) if tx.Error != nil { return tx.Error } @@ -77,13 +76,15 @@ func (a *ApiKeyStore) Save(apiKey *apikey.ApiKey) error { return nil } -func (a *ApiKeyStore) Delete(apiKey *apikey.ApiKey) error { - tx := a.db.Where("key_hash = ?", apiKey.KeyHash).Delete(&ApiKeyDTO{}) +func (a *ApiKeyStore) Delete(ctx context.Context, apiKey *models.ApiKey) error { + tx := a.GetTransaction(ctx) + + tx = tx.Where("key_hash = ?", apiKey.KeyHash).Delete(&models.ApiKey{}) if tx.Error != nil { return tx.Error } if tx.RowsAffected == 0 { - return apikey.ErrApiKeyNotFound + return stores.ErrApiKeyNotFound } return nil diff --git a/pkg/db/build_store.go b/pkg/db/build_store.go index e92aeec95f..0ff66c60f5 100644 --- a/pkg/db/build_store.go +++ b/pkg/db/build_store.go @@ -4,75 +4,73 @@ package db import ( + "context" "encoding/json" "fmt" "strings" "sync" - "github.com/daytonaio/daytona/pkg/build" - . "github.com/daytonaio/daytona/pkg/db/dto" - "github.com/daytonaio/daytona/pkg/workspace/project/buildconfig" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/stores" "gorm.io/gorm" ) type BuildStore struct { - db *gorm.DB + IStore Lock sync.Mutex } -func NewBuildStore(db *gorm.DB) (*BuildStore, error) { - err := db.AutoMigrate(&BuildDTO{}) +func NewBuildStore(store IStore) (stores.BuildStore, error) { + err := store.AutoMigrate(&models.Build{}) if err != nil { return nil, err } - return &BuildStore{db: db}, nil + return &BuildStore{store, sync.Mutex{}}, nil } -func (b *BuildStore) Find(filter *build.Filter) (*build.Build, error) { +func (b *BuildStore) Find(ctx context.Context, filter *stores.BuildFilter) (*models.Build, error) { b.Lock.Lock() defer b.Lock.Unlock() - buildDTO := BuildDTO{} - tx := processBuildFilters(b.db, filter).First(&buildDTO) + tx := b.GetTransaction(ctx) + + build := &models.Build{} + tx = preloadBuildEntities(processBuildFilters(tx, filter)).First(build) if tx.Error != nil { if tx.Error == gorm.ErrRecordNotFound { - return nil, build.ErrBuildNotFound + return nil, stores.ErrBuildNotFound } return nil, tx.Error } - build := ToBuild(buildDTO) - return build, nil } -func (b *BuildStore) List(filter *build.Filter) ([]*build.Build, error) { +func (b *BuildStore) List(ctx context.Context, filter *stores.BuildFilter) ([]*models.Build, error) { b.Lock.Lock() defer b.Lock.Unlock() - buildDTOs := []BuildDTO{} - tx := processBuildFilters(b.db, filter).Find(&buildDTOs) + tx := b.GetTransaction(ctx) + + builds := []*models.Build{} + tx = preloadBuildEntities(processBuildFilters(tx, filter)).Find(&builds) if tx.Error != nil { return nil, tx.Error } - builds := []*build.Build{} - for _, buildDTO := range buildDTOs { - builds = append(builds, ToBuild(buildDTO)) - } - return builds, nil } -func (b *BuildStore) Save(build *build.Build) error { +func (b *BuildStore) Save(ctx context.Context, build *models.Build) error { b.Lock.Lock() defer b.Lock.Unlock() - buildDTO := ToBuildDTO(build) - tx := b.db.Save(&buildDTO) + tx := b.GetTransaction(ctx) + + tx = tx.Save(build) if tx.Error != nil { return tx.Error } @@ -80,32 +78,31 @@ func (b *BuildStore) Save(build *build.Build) error { return nil } -func (b *BuildStore) Delete(id string) error { +func (b *BuildStore) Delete(ctx context.Context, id string) error { b.Lock.Lock() defer b.Lock.Unlock() + tx := b.GetTransaction(ctx) - tx := b.db.Where("id = ?", id).Delete(&BuildDTO{}) + tx = tx.Where("id = ?", id).Delete(&models.Build{}) if tx.Error != nil { return tx.Error } if tx.RowsAffected == 0 { - return build.ErrBuildNotFound + return stores.ErrBuildNotFound } return nil } -func processBuildFilters(tx *gorm.DB, filter *build.Filter) *gorm.DB { +func preloadBuildEntities(tx *gorm.DB) *gorm.DB { + return tx.Preload("LastJob") +} + +func processBuildFilters(tx *gorm.DB, filter *stores.BuildFilter) *gorm.DB { if filter != nil { if filter.Id != nil { tx = tx.Where("id = ?", *filter.Id) } - if filter.States != nil && len(*filter.States) > 0 { - placeholders := strings.Repeat("?,", len(*filter.States)) - placeholders = placeholders[:len(placeholders)-1] - - tx = tx.Where(fmt.Sprintf("state IN (%s)", placeholders), filter.StatesToInterface()...) - } if filter.PrebuildIds != nil && len(*filter.PrebuildIds) > 0 { placeholders := strings.Repeat("?,", len(*filter.PrebuildIds)) placeholders = placeholders[:len(placeholders)-1] @@ -116,7 +113,7 @@ func processBuildFilters(tx *gorm.DB, filter *build.Filter) *gorm.DB { tx = tx.Order("created_at desc").Limit(1) } // Skip filtering when an automatic build config is provided - if filter.BuildConfig != nil && *filter.BuildConfig != (buildconfig.BuildConfig{}) { + if filter.BuildConfig != nil && *filter.BuildConfig != (models.BuildConfig{}) { buildConfigJSON, err := json.Marshal(filter.BuildConfig) if err == nil { tx = tx.Where("build_config = ?", string(buildConfigJSON)) diff --git a/pkg/db/connection.go b/pkg/db/connection.go index 1d791b6137..3b058722cb 100644 --- a/pkg/db/connection.go +++ b/pkg/db/connection.go @@ -44,6 +44,12 @@ func GetSQLiteConnection(dbPath string) *gorm.DB { if err != nil { panic("failed to connect database") } + sqlDB, err := db.DB() + if err != nil { + panic("failed to connect database") + } + + sqlDB.SetMaxOpenConns(1) _db = db diff --git a/pkg/db/container_registry_store.go b/pkg/db/container_registry_store.go deleted file mode 100644 index d4f18b9085..0000000000 --- a/pkg/db/container_registry_store.go +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package db - -import ( - "gorm.io/gorm" - - "github.com/daytonaio/daytona/pkg/containerregistry" - . "github.com/daytonaio/daytona/pkg/db/dto" -) - -type ContainerRegistryStore struct { - db *gorm.DB -} - -func NewContainerRegistryStore(db *gorm.DB) (*ContainerRegistryStore, error) { - err := db.AutoMigrate(&ContainerRegistryDTO{}) - if err != nil { - return nil, err - } - - return &ContainerRegistryStore{db: db}, nil -} - -func (s *ContainerRegistryStore) List() ([]*containerregistry.ContainerRegistry, error) { - containerRegistryDTOs := []ContainerRegistryDTO{} - tx := s.db.Find(&containerRegistryDTOs) - if tx.Error != nil { - return nil, tx.Error - } - - containerregistryTargets := []*containerregistry.ContainerRegistry{} - for _, containerRegistryDTO := range containerRegistryDTOs { - containerregistryTargets = append(containerregistryTargets, ToContainerRegistry(containerRegistryDTO)) - } - - return containerregistryTargets, nil -} - -func (s *ContainerRegistryStore) Find(server string) (*containerregistry.ContainerRegistry, error) { - containerRegistryDTO := ContainerRegistryDTO{} - tx := s.db.Where("server = ?", server).First(&containerRegistryDTO) - if tx.Error != nil { - if IsRecordNotFound(tx.Error) { - return nil, containerregistry.ErrContainerRegistryNotFound - } - return nil, tx.Error - } - - return ToContainerRegistry(containerRegistryDTO), nil -} - -func (s *ContainerRegistryStore) Save(cr *containerregistry.ContainerRegistry) error { - tx := s.db.Save(ToContainerRegistryDTO(cr)) - if tx.Error != nil { - return tx.Error - } - - return nil -} - -func (s *ContainerRegistryStore) Delete(cr *containerregistry.ContainerRegistry) error { - tx := s.db.Delete(ToContainerRegistryDTO(cr)) - if tx.Error != nil { - return tx.Error - } - if tx.RowsAffected == 0 { - return containerregistry.ErrContainerRegistryNotFound - } - - return nil -} diff --git a/pkg/db/db_store.go b/pkg/db/db_store.go new file mode 100644 index 0000000000..96a53faa87 --- /dev/null +++ b/pkg/db/db_store.go @@ -0,0 +1,77 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package db + +import ( + "context" + "fmt" + + "gorm.io/gorm" + + "github.com/daytonaio/daytona/pkg/stores" +) + +type IStore interface { + stores.IStore + AutoMigrate(...interface{}) error + GetTransaction(ctx context.Context) *gorm.DB +} + +type dbStore struct { + db *gorm.DB +} + +func NewStore(db *gorm.DB) IStore { + return &dbStore{db} +} + +func (s *dbStore) AutoMigrate(dst ...interface{}) error { + return s.db.AutoMigrate(dst...) +} + +func (s *dbStore) BeginTransaction(ctx context.Context) (context.Context, error) { + if ctx.Value(stores.TransactionKey{}) != nil { + return ctx, nil + } + + tx := s.db.Begin() + if tx.Error != nil { + return nil, tx.Error + } + + ctx = context.WithValue(ctx, stores.TransactionKey{}, tx) + return ctx, nil +} + +func (s *dbStore) CommitTransaction(ctx context.Context) error { + tx, ok := ctx.Value(stores.TransactionKey{}).(*gorm.DB) + if !ok { + return nil + } + + return tx.Commit().Error +} + +func (s *dbStore) RollbackTransaction(ctx context.Context, err error) error { + tx, ok := ctx.Value(stores.TransactionKey{}).(*gorm.DB) + if !ok { + return err + } + + txErr := tx.Rollback().Error + if txErr == nil { + return err + } + + return fmt.Errorf("%w. Transaction rollback error: %w", err, txErr) +} + +func (s *dbStore) GetTransaction(ctx context.Context) *gorm.DB { + tx, ok := ctx.Value(stores.TransactionKey{}).(*gorm.DB) + if !ok { + return s.db + } + + return tx +} diff --git a/pkg/db/dto/api_key.go b/pkg/db/dto/api_key.go deleted file mode 100644 index 4de69738f1..0000000000 --- a/pkg/db/dto/api_key.go +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package dto - -import ( - "github.com/daytonaio/daytona/pkg/apikey" -) - -type ApiKeyDTO struct { - KeyHash string `gorm:"primaryKey"` - Type apikey.ApiKeyType - Name string `gorm:"uniqueIndex"` -} - -func ToApiKeyDTO(apiKey apikey.ApiKey) ApiKeyDTO { - return ApiKeyDTO{ - KeyHash: apiKey.KeyHash, - Type: apiKey.Type, - Name: apiKey.Name, - } -} - -func ToApiKey(apiKeyDTO ApiKeyDTO) apikey.ApiKey { - return apikey.ApiKey{ - KeyHash: apiKeyDTO.KeyHash, - Type: apiKeyDTO.Type, - Name: apiKeyDTO.Name, - } -} diff --git a/pkg/db/dto/build.go b/pkg/db/dto/build.go deleted file mode 100644 index 6da3818196..0000000000 --- a/pkg/db/dto/build.go +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package dto - -import ( - "time" - - "github.com/daytonaio/daytona/pkg/build" - "github.com/daytonaio/daytona/pkg/workspace/project/containerconfig" -) - -type BuildDTO struct { - Id string `json:"id" gorm:"primaryKey"` - State string `json:"state"` - Image *string `json:"image,omitempty"` - User *string `json:"user,omitempty"` - ContainerConfig containerconfig.ContainerConfig `gorm:"serializer:json"` - BuildConfig *ProjectBuildDTO `json:"build,omitempty" gorm:"serializer:json"` - Repository RepositoryDTO `gorm:"serializer:json"` - EnvVars map[string]string `json:"envVars" gorm:"serializer:json"` - PrebuildId string `json:"prebuildId"` - CreatedAt time.Time `json:"createdAt"` - UpdatedAt time.Time `json:"updatedAt"` -} - -func ToBuildDTO(build *build.Build) BuildDTO { - return BuildDTO{ - Id: build.Id, - State: string(build.State), - Image: build.Image, - User: build.User, - ContainerConfig: build.ContainerConfig, - BuildConfig: ToProjectBuildDTO(build.BuildConfig), - Repository: ToRepositoryDTO(build.Repository), - EnvVars: build.EnvVars, - PrebuildId: build.PrebuildId, - CreatedAt: build.CreatedAt, - UpdatedAt: build.UpdatedAt, - } -} - -func ToBuild(buildDTO BuildDTO) *build.Build { - return &build.Build{ - Id: buildDTO.Id, - State: build.BuildState(buildDTO.State), - Image: buildDTO.Image, - User: buildDTO.User, - ContainerConfig: buildDTO.ContainerConfig, - BuildConfig: ToProjectBuild(buildDTO.BuildConfig), - Repository: ToRepository(buildDTO.Repository), - EnvVars: buildDTO.EnvVars, - PrebuildId: buildDTO.PrebuildId, - CreatedAt: buildDTO.CreatedAt, - UpdatedAt: buildDTO.UpdatedAt, - } -} diff --git a/pkg/db/dto/container_registry.go b/pkg/db/dto/container_registry.go deleted file mode 100644 index c5ae103957..0000000000 --- a/pkg/db/dto/container_registry.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package dto - -import ( - "github.com/daytonaio/daytona/pkg/containerregistry" -) - -type ContainerRegistryDTO struct { - Server string `gorm:"primaryKey"` - Username string `json:"username"` - Password string `json:"password"` -} - -func ToContainerRegistryDTO(cr *containerregistry.ContainerRegistry) ContainerRegistryDTO { - dto := ContainerRegistryDTO{ - Server: cr.Server, - Username: cr.Username, - Password: cr.Password, - } - - return dto -} - -func ToContainerRegistry(dto ContainerRegistryDTO) *containerregistry.ContainerRegistry { - cr := containerregistry.ContainerRegistry{ - Server: dto.Server, - Username: dto.Username, - Password: dto.Password, - } - - return &cr -} diff --git a/pkg/db/dto/git_provider.go b/pkg/db/dto/git_provider.go deleted file mode 100644 index d08bb586e7..0000000000 --- a/pkg/db/dto/git_provider.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package dto - -import ( - "github.com/daytonaio/daytona/pkg/gitprovider" -) - -type GitProviderConfigDTO struct { - Id string `gorm:"primaryKey"` - ProviderId string `json:"providerId"` - Username string `json:"username"` - Token string `json:"token"` - BaseApiUrl *string `json:"baseApiUrl,omitempty"` - Alias string `gorm:"uniqueIndex" json:"alias"` - SigningKey *string `json:"siginingKey,omitempty"` - SigningMethod *gitprovider.SigningMethod `json:"siginingMethod,omitempty"` -} - -func ToGitProviderConfigDTO(gitProvider gitprovider.GitProviderConfig) GitProviderConfigDTO { - gitProviderDTO := GitProviderConfigDTO{ - Id: gitProvider.Id, - ProviderId: gitProvider.ProviderId, - Username: gitProvider.Username, - Token: gitProvider.Token, - BaseApiUrl: gitProvider.BaseApiUrl, - Alias: gitProvider.Alias, - SigningKey: gitProvider.SigningKey, - SigningMethod: gitProvider.SigningMethod, - } - - return gitProviderDTO -} - -func ToGitProviderConfig(gitProviderDTO GitProviderConfigDTO) gitprovider.GitProviderConfig { - return gitprovider.GitProviderConfig{ - Id: gitProviderDTO.Id, - ProviderId: gitProviderDTO.ProviderId, - Username: gitProviderDTO.Username, - Token: gitProviderDTO.Token, - BaseApiUrl: gitProviderDTO.BaseApiUrl, - Alias: gitProviderDTO.Alias, - SigningKey: gitProviderDTO.SigningKey, - SigningMethod: gitProviderDTO.SigningMethod, - } -} diff --git a/pkg/db/dto/profile_data.go b/pkg/db/dto/profile_data.go deleted file mode 100644 index 4dbb448adb..0000000000 --- a/pkg/db/dto/profile_data.go +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package dto - -import "github.com/daytonaio/daytona/pkg/profiledata" - -const ProfileDataId = "profile_data" - -type ProfileDataDTO struct { - Id string `gorm:"primaryKey"` - EnvVars map[string]string `gorm:"serializer:json"` -} - -func ToProfileDataDTO(profileData *profiledata.ProfileData) ProfileDataDTO { - return ProfileDataDTO{ - Id: ProfileDataId, - EnvVars: profileData.EnvVars, - } -} - -func ToProfileData(profileDataDTO ProfileDataDTO) *profiledata.ProfileData { - return &profiledata.ProfileData{ - EnvVars: profileDataDTO.EnvVars, - } -} diff --git a/pkg/db/dto/project.go b/pkg/db/dto/project.go deleted file mode 100644 index 04a34d4372..0000000000 --- a/pkg/db/dto/project.go +++ /dev/null @@ -1,249 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package dto - -import ( - "github.com/daytonaio/daytona/pkg/gitprovider" - "github.com/daytonaio/daytona/pkg/workspace/project" - "github.com/daytonaio/daytona/pkg/workspace/project/buildconfig" -) - -type RepositoryDTO struct { - Id string `json:"id"` - Url string `json:"url"` - Name string `json:"name"` - Owner string `json:"owner"` - Sha string `json:"sha"` - Source string `json:"source"` - Branch string `json:"branch"` - PrNumber *uint32 `json:"prNumber,omitempty"` - Path *string `json:"path,omitempty"` - Target gitprovider.CloneTarget `json:"cloneTarget,omitempty"` -} - -type FileStatusDTO struct { - Name string `json:"name"` - Extra string `json:"extra"` - Staging string `json:"staging"` - Worktree string `json:"worktree"` -} - -type GitStatusDTO struct { - CurrentBranch string `json:"currentBranch"` - Files []*FileStatusDTO `json:"fileStatus"` - BranchPublished bool `json:"branchPublished,omitempty"` - Ahead int32 `json:"ahead,omitempty"` - Behind int32 `json:"behind,omitempty"` -} - -type ProjectStateDTO struct { - UpdatedAt string `json:"updatedAt"` - Uptime uint64 `json:"uptime"` - GitStatus *GitStatusDTO `json:"gitStatus"` -} - -type ProjectBuildDevcontainerDTO struct { - FilePath string `json:"filePath"` -} - -type ProjectBuildDTO struct { - Devcontainer *ProjectBuildDevcontainerDTO `json:"devcontainer"` -} - -type ProjectDTO struct { - Name string `json:"name"` - Image string `json:"image"` - User string `json:"user"` - Build *ProjectBuildDTO `json:"build,omitempty" gorm:"serializer:json"` - Repository RepositoryDTO `json:"repository" gorm:"serializer:json"` - WorkspaceId string `json:"workspaceId"` - Target string `json:"target"` - ApiKey string `json:"apiKey"` - State *ProjectStateDTO `json:"state,omitempty" gorm:"serializer:json"` - GitProviderConfigId *string `json:"gitProviderConfigId,omitempty"` -} - -func ToProjectDTO(project *project.Project) ProjectDTO { - return ProjectDTO{ - Name: project.Name, - Image: project.Image, - User: project.User, - Build: ToProjectBuildDTO(project.BuildConfig), - Repository: ToRepositoryDTO(project.Repository), - WorkspaceId: project.WorkspaceId, - Target: project.Target, - State: ToProjectStateDTO(project.State), - ApiKey: project.ApiKey, - GitProviderConfigId: project.GitProviderConfigId, - } -} - -func ToRepositoryDTO(repo *gitprovider.GitRepository) RepositoryDTO { - repoDTO := RepositoryDTO{ - Url: repo.Url, - Name: repo.Name, - Id: repo.Id, - Owner: repo.Owner, - Sha: repo.Sha, - Source: repo.Source, - Branch: repo.Branch, - PrNumber: repo.PrNumber, - Path: repo.Path, - Target: repo.Target, - } - - return repoDTO -} - -func ToFileStatusDTO(status *project.FileStatus) *FileStatusDTO { - if status == nil { - return nil - } - - return &FileStatusDTO{ - Name: status.Name, - Extra: status.Extra, - Staging: string(status.Staging), - Worktree: string(status.Worktree), - } -} - -func ToGitStatusDTO(status *project.GitStatus) *GitStatusDTO { - if status == nil { - return nil - } - - statusDTO := &GitStatusDTO{ - CurrentBranch: status.CurrentBranch, - BranchPublished: status.BranchPublished, - Ahead: int32(status.Ahead), - Behind: int32(status.Behind), - } - - for _, file := range status.Files { - statusDTO.Files = append(statusDTO.Files, ToFileStatusDTO(file)) - } - - return statusDTO -} - -func ToProjectStateDTO(state *project.ProjectState) *ProjectStateDTO { - if state == nil { - return nil - } - - return &ProjectStateDTO{ - UpdatedAt: state.UpdatedAt, - Uptime: state.Uptime, - GitStatus: ToGitStatusDTO(state.GitStatus), - } -} - -func ToProjectBuildDTO(build *buildconfig.BuildConfig) *ProjectBuildDTO { - if build == nil { - return nil - } - - if build.Devcontainer == nil { - return &ProjectBuildDTO{} - } - - return &ProjectBuildDTO{ - Devcontainer: &ProjectBuildDevcontainerDTO{ - FilePath: build.Devcontainer.FilePath, - }, - } -} - -func ToProject(projectDTO ProjectDTO) *project.Project { - return &project.Project{ - Name: projectDTO.Name, - Image: projectDTO.Image, - User: projectDTO.User, - BuildConfig: ToProjectBuild(projectDTO.Build), - Repository: ToRepository(projectDTO.Repository), - WorkspaceId: projectDTO.WorkspaceId, - Target: projectDTO.Target, - State: ToProjectState(projectDTO.State), - ApiKey: projectDTO.ApiKey, - GitProviderConfigId: projectDTO.GitProviderConfigId, - } -} - -func ToFileStatus(statusDTO *FileStatusDTO) *project.FileStatus { - if statusDTO == nil { - return nil - } - - return &project.FileStatus{ - Name: statusDTO.Name, - Extra: statusDTO.Extra, - Staging: project.Status(statusDTO.Staging), - Worktree: project.Status(statusDTO.Worktree), - } -} - -func ToGitStatus(statusDTO *GitStatusDTO) *project.GitStatus { - if statusDTO == nil { - return nil - } - - status := &project.GitStatus{ - CurrentBranch: statusDTO.CurrentBranch, - BranchPublished: statusDTO.BranchPublished, - Ahead: int(statusDTO.Ahead), - Behind: int(statusDTO.Behind), - } - - for _, file := range statusDTO.Files { - status.Files = append(status.Files, ToFileStatus(file)) - } - - return status -} - -func ToProjectState(stateDTO *ProjectStateDTO) *project.ProjectState { - if stateDTO == nil { - return nil - } - - return &project.ProjectState{ - UpdatedAt: stateDTO.UpdatedAt, - Uptime: stateDTO.Uptime, - GitStatus: ToGitStatus(stateDTO.GitStatus), - } -} - -func ToRepository(repoDTO RepositoryDTO) *gitprovider.GitRepository { - repo := gitprovider.GitRepository{ - Url: repoDTO.Url, - Id: repoDTO.Id, - Name: repoDTO.Name, - Owner: repoDTO.Owner, - Branch: repoDTO.Branch, - Sha: repoDTO.Sha, - PrNumber: repoDTO.PrNumber, - Source: repoDTO.Source, - Path: repoDTO.Path, - Target: gitprovider.CloneTarget(repoDTO.Target), - } - - return &repo -} - -func ToProjectBuild(buildDTO *ProjectBuildDTO) *buildconfig.BuildConfig { - if buildDTO == nil { - return nil - } - - if buildDTO.Devcontainer == nil { - return &buildconfig.BuildConfig{} - } - - return &buildconfig.BuildConfig{ - Devcontainer: &buildconfig.DevcontainerConfig{ - FilePath: buildDTO.Devcontainer.FilePath, - }, - } -} diff --git a/pkg/db/dto/project_config.go b/pkg/db/dto/project_config.go deleted file mode 100644 index a0a5f9c92a..0000000000 --- a/pkg/db/dto/project_config.go +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package dto - -import ( - "github.com/daytonaio/daytona/pkg/workspace/project/config" -) - -type ProjectConfigDTO struct { - Name string `gorm:"primaryKey"` - Image string `json:"image"` - User string `json:"user"` - Build *ProjectBuildDTO `json:"build,omitempty" gorm:"serializer:json"` - RepositoryUrl string `json:"repositoryUrl"` - EnvVars map[string]string `json:"envVars" gorm:"serializer:json"` - Prebuilds []PrebuildDTO `gorm:"serializer:json"` - IsDefault bool `json:"isDefault"` - GitProviderConfigId *string `json:"gitProviderConfigId" validate:"optional"` -} - -type PrebuildDTO struct { - Id string `json:"id"` - Branch string `json:"branch"` - CommitInterval *int `json:"commitInterval,omitempty"` - TriggerFiles []string `json:"triggerFiles,omitempty"` - Retention int `json:"retention"` -} - -func ToProjectConfigDTO(projectConfig *config.ProjectConfig) ProjectConfigDTO { - prebuilds := []PrebuildDTO{} - for _, prebuild := range projectConfig.Prebuilds { - prebuilds = append(prebuilds, ToPrebuildDTO(prebuild)) - } - - return ProjectConfigDTO{ - Name: projectConfig.Name, - Image: projectConfig.Image, - User: projectConfig.User, - Build: ToProjectBuildDTO(projectConfig.BuildConfig), - RepositoryUrl: projectConfig.RepositoryUrl, - EnvVars: projectConfig.EnvVars, - Prebuilds: prebuilds, - IsDefault: projectConfig.IsDefault, - GitProviderConfigId: projectConfig.GitProviderConfigId, - } -} - -func ToProjectConfig(projectConfigDTO ProjectConfigDTO) *config.ProjectConfig { - prebuilds := []*config.PrebuildConfig{} - for _, prebuildDTO := range projectConfigDTO.Prebuilds { - prebuilds = append(prebuilds, ToPrebuild(prebuildDTO)) - } - - return &config.ProjectConfig{ - Name: projectConfigDTO.Name, - Image: projectConfigDTO.Image, - User: projectConfigDTO.User, - BuildConfig: ToProjectBuild(projectConfigDTO.Build), - RepositoryUrl: projectConfigDTO.RepositoryUrl, - EnvVars: projectConfigDTO.EnvVars, - Prebuilds: prebuilds, - IsDefault: projectConfigDTO.IsDefault, - GitProviderConfigId: projectConfigDTO.GitProviderConfigId, - } -} - -func ToPrebuildDTO(prebuild *config.PrebuildConfig) PrebuildDTO { - return PrebuildDTO{ - Id: prebuild.Id, - Branch: prebuild.Branch, - CommitInterval: prebuild.CommitInterval, - TriggerFiles: prebuild.TriggerFiles, - Retention: prebuild.Retention, - } -} - -func ToPrebuild(prebuildDTO PrebuildDTO) *config.PrebuildConfig { - return &config.PrebuildConfig{ - Id: prebuildDTO.Id, - Branch: prebuildDTO.Branch, - CommitInterval: prebuildDTO.CommitInterval, - TriggerFiles: prebuildDTO.TriggerFiles, - Retention: prebuildDTO.Retention, - } -} diff --git a/pkg/db/dto/provider_target.go b/pkg/db/dto/provider_target.go deleted file mode 100644 index 53f03752e6..0000000000 --- a/pkg/db/dto/provider_target.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package dto - -import "github.com/daytonaio/daytona/pkg/provider" - -type ProviderTargetDTO struct { - Name string `json:"name" gorm:"primaryKey"` - ProviderName string `json:"providerName"` - ProviderLabel *string `json:"providerLabel,omitempty"` - ProviderVersion string `json:"providerVersion"` - Options string `json:"options"` - IsDefault bool `json:"isDefault"` -} - -func ToProviderTargetDTO(providerTarget *provider.ProviderTarget) ProviderTargetDTO { - return ProviderTargetDTO{ - Name: providerTarget.Name, - ProviderName: providerTarget.ProviderInfo.Name, - ProviderLabel: providerTarget.ProviderInfo.Label, - ProviderVersion: providerTarget.ProviderInfo.Version, - Options: providerTarget.Options, - IsDefault: providerTarget.IsDefault, - } -} - -func ToProviderTarget(providerTargetDTO ProviderTargetDTO) *provider.ProviderTarget { - return &provider.ProviderTarget{ - Name: providerTargetDTO.Name, - ProviderInfo: provider.ProviderInfo{ - Name: providerTargetDTO.ProviderName, - Label: providerTargetDTO.ProviderLabel, - Version: providerTargetDTO.ProviderVersion, - }, - Options: providerTargetDTO.Options, - IsDefault: providerTargetDTO.IsDefault, - } -} diff --git a/pkg/db/dto/workspace.go b/pkg/db/dto/workspace.go deleted file mode 100644 index 09976cf243..0000000000 --- a/pkg/db/dto/workspace.go +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package dto - -import ( - "errors" - - "github.com/daytonaio/daytona/pkg/workspace" -) - -type WorkspaceDTO struct { - Id string `gorm:"primaryKey"` - Name string `json:"name" gorm:"unique"` - Target string `json:"target"` - ApiKey string `json:"apiKey"` - Projects []ProjectDTO `gorm:"serializer:json"` -} - -func (w WorkspaceDTO) GetProject(name string) (*ProjectDTO, error) { - for _, project := range w.Projects { - if project.Name == name { - return &project, nil - } - } - - return nil, errors.New("project not found") -} - -func ToWorkspaceDTO(workspace *workspace.Workspace) WorkspaceDTO { - workspaceDTO := WorkspaceDTO{ - Id: workspace.Id, - Name: workspace.Name, - Target: workspace.Target, - ApiKey: workspace.ApiKey, - } - - for _, project := range workspace.Projects { - workspaceDTO.Projects = append(workspaceDTO.Projects, ToProjectDTO(project)) - } - - return workspaceDTO -} - -func ToWorkspace(workspaceDTO WorkspaceDTO) *workspace.Workspace { - workspace := workspace.Workspace{ - Id: workspaceDTO.Id, - Name: workspaceDTO.Name, - Target: workspaceDTO.Target, - ApiKey: workspaceDTO.ApiKey, - } - - for _, projectDTO := range workspaceDTO.Projects { - workspace.Projects = append(workspace.Projects, ToProject(projectDTO)) - } - - return &workspace -} diff --git a/pkg/db/env_store.go b/pkg/db/env_store.go new file mode 100644 index 0000000000..1d7bcad45b --- /dev/null +++ b/pkg/db/env_store.go @@ -0,0 +1,65 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package db + +import ( + "context" + + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/stores" + "gorm.io/gorm" +) + +type EnvironmentVariableStore struct { + IStore +} + +func NewEnvironmentVariableStore(store IStore) (stores.EnvironmentVariableStore, error) { + err := store.AutoMigrate(&models.EnvironmentVariable{}) + if err != nil { + return nil, err + } + + return &EnvironmentVariableStore{store}, nil +} + +func (store *EnvironmentVariableStore) List(ctx context.Context) ([]*models.EnvironmentVariable, error) { + tx := store.GetTransaction(ctx) + + environmentVariables := []*models.EnvironmentVariable{} + tx = tx.Find(&environmentVariables) + if tx.Error != nil { + if tx.Error == gorm.ErrRecordNotFound { + return nil, stores.ErrEnvironmentVariableNotFound + } + return nil, tx.Error + } + + return environmentVariables, nil +} + +func (store *EnvironmentVariableStore) Save(ctx context.Context, environmentVariable *models.EnvironmentVariable) error { + tx := store.GetTransaction(ctx) + + tx = tx.Save(environmentVariable) + if tx.Error != nil { + return tx.Error + } + + return nil +} + +func (store *EnvironmentVariableStore) Delete(ctx context.Context, key string) error { + tx := store.GetTransaction(ctx) + + tx = tx.Where("key = ?", key).Delete(&models.EnvironmentVariable{}) + if tx.Error != nil { + return tx.Error + } + if tx.RowsAffected == 0 { + return stores.ErrEnvironmentVariableNotFound + } + + return nil +} diff --git a/pkg/db/gitprovider_config_store.go b/pkg/db/gitprovider_config_store.go index 07c55b4d67..c1b2c6a731 100644 --- a/pkg/db/gitprovider_config_store.go +++ b/pkg/db/gitprovider_config_store.go @@ -4,59 +4,56 @@ package db import ( - "gorm.io/gorm" + "context" - . "github.com/daytonaio/daytona/pkg/db/dto" - "github.com/daytonaio/daytona/pkg/gitprovider" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/stores" ) type GitProviderConfigStore struct { - db *gorm.DB + IStore } -func NewGitProviderConfigStore(db *gorm.DB) (*GitProviderConfigStore, error) { - err := db.AutoMigrate(&GitProviderConfigDTO{}) +func NewGitProviderConfigStore(store IStore) (stores.GitProviderConfigStore, error) { + err := store.AutoMigrate(&models.GitProviderConfig{}) if err != nil { return nil, err } - return &GitProviderConfigStore{db: db}, nil + return &GitProviderConfigStore{store}, nil } -func (p *GitProviderConfigStore) List() ([]*gitprovider.GitProviderConfig, error) { - gitProviderDTOs := []GitProviderConfigDTO{} - tx := p.db.Find(&gitProviderDTOs) +func (p *GitProviderConfigStore) List(ctx context.Context) ([]*models.GitProviderConfig, error) { + tx := p.GetTransaction(ctx) + + gitProviders := []*models.GitProviderConfig{} + tx = tx.Find(&gitProviders) if tx.Error != nil { return nil, tx.Error } - gitProviders := []*gitprovider.GitProviderConfig{} - for _, gitProviderDTO := range gitProviderDTOs { - gitProvider := ToGitProviderConfig(gitProviderDTO) - gitProviders = append(gitProviders, &gitProvider) - } - return gitProviders, nil } -func (p *GitProviderConfigStore) Find(id string) (*gitprovider.GitProviderConfig, error) { - gitProviderDTO := GitProviderConfigDTO{} - tx := p.db.Where("id = ?", id).First(&gitProviderDTO) +func (p *GitProviderConfigStore) Find(ctx context.Context, id string) (*models.GitProviderConfig, error) { + tx := p.GetTransaction(ctx) + + gitProvider := &models.GitProviderConfig{} + tx = tx.Where("id = ?", id).First(gitProvider) if tx.Error != nil { if IsRecordNotFound(tx.Error) { - return nil, gitprovider.ErrGitProviderConfigNotFound + return nil, stores.ErrGitProviderConfigNotFound } return nil, tx.Error } - gitProvider := ToGitProviderConfig(gitProviderDTO) - - return &gitProvider, nil + return gitProvider, nil } -func (p *GitProviderConfigStore) Save(gitProvider *gitprovider.GitProviderConfig) error { - gitProviderDTO := ToGitProviderConfigDTO(*gitProvider) - tx := p.db.Save(&gitProviderDTO) +func (p *GitProviderConfigStore) Save(ctx context.Context, gitProvider *models.GitProviderConfig) error { + tx := p.GetTransaction(ctx) + + tx = tx.Save(gitProvider) if tx.Error != nil { return tx.Error } @@ -64,14 +61,15 @@ func (p *GitProviderConfigStore) Save(gitProvider *gitprovider.GitProviderConfig return nil } -func (p *GitProviderConfigStore) Delete(gitProvider *gitprovider.GitProviderConfig) error { - gitProviderDTO := ToGitProviderConfigDTO(*gitProvider) - tx := p.db.Delete(&gitProviderDTO) +func (p *GitProviderConfigStore) Delete(ctx context.Context, gitProvider *models.GitProviderConfig) error { + tx := p.GetTransaction(ctx) + + tx = tx.Delete(gitProvider) if tx.Error != nil { return tx.Error } if tx.RowsAffected == 0 { - return gitprovider.ErrGitProviderConfigNotFound + return stores.ErrGitProviderConfigNotFound } return nil diff --git a/pkg/db/job_store.go b/pkg/db/job_store.go new file mode 100644 index 0000000000..f398e209a5 --- /dev/null +++ b/pkg/db/job_store.go @@ -0,0 +1,111 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package db + +import ( + "context" + "fmt" + "strings" + + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/stores" + "gorm.io/gorm" +) + +type JobStore struct { + IStore +} + +func NewJobStore(store IStore) (stores.JobStore, error) { + err := store.AutoMigrate(&models.Job{}) + if err != nil { + return nil, err + } + + return &JobStore{store}, nil +} + +func (s *JobStore) List(ctx context.Context, filter *stores.JobFilter) ([]*models.Job, error) { + tx := s.GetTransaction(ctx) + + jobs := []*models.Job{} + tx = processJobFilters(tx, filter).Find(&jobs) + + if tx.Error != nil { + return nil, tx.Error + } + + return jobs, nil +} + +func (s *JobStore) Find(ctx context.Context, filter *stores.JobFilter) (*models.Job, error) { + tx := s.GetTransaction(ctx) + + job := &models.Job{} + tx = processJobFilters(tx, filter).First(&job) + if tx.Error != nil { + if IsRecordNotFound(tx.Error) { + return nil, stores.ErrJobNotFound + } + return nil, tx.Error + } + + return job, nil + +} + +func (s *JobStore) Save(ctx context.Context, job *models.Job) error { + tx := s.GetTransaction(ctx) + + tx = tx.Save(job) + if tx.Error != nil { + return tx.Error + } + + return nil +} + +func (s *JobStore) Delete(ctx context.Context, job *models.Job) error { + tx := s.GetTransaction(ctx) + + tx = tx.Delete(job) + if tx.Error != nil { + return tx.Error + } + if tx.RowsAffected == 0 { + return stores.ErrJobNotFound + } + + return nil +} + +func processJobFilters(tx *gorm.DB, filter *stores.JobFilter) *gorm.DB { + if filter != nil { + if filter.Id != nil { + tx = tx.Where("id = ?", *filter.Id) + } + if filter.ResourceType != nil { + tx = tx.Where("resource_type = ?", *filter.ResourceType) + } + if filter.ResourceId != nil { + tx = tx.Where("resource_id = ?", *filter.ResourceId) + } + if filter.RunnerIdOrIsNil != nil { + tx = tx.Where("runner_id = ? OR runner_id IS NULL OR runner_id = ''", *filter.RunnerIdOrIsNil) + } + if filter.States != nil && len(*filter.States) > 0 { + placeholders := strings.Repeat("?,", len(*filter.States)) + placeholders = placeholders[:len(placeholders)-1] + + tx = tx.Where(fmt.Sprintf("state IN (%s)", placeholders), filter.StatesToInterface()...) + } + if filter.Actions != nil && len(*filter.Actions) > 0 { + placeholders := strings.Repeat("?,", len(*filter.Actions)) + placeholders = placeholders[:len(placeholders)-1] + + tx = tx.Where(fmt.Sprintf("action IN (%s)", placeholders), filter.ActionsToInterface()...) + } + } + return tx +} diff --git a/pkg/db/profile_data_store.go b/pkg/db/profile_data_store.go deleted file mode 100644 index 0a5589bae3..0000000000 --- a/pkg/db/profile_data_store.go +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package db - -import ( - . "github.com/daytonaio/daytona/pkg/db/dto" - "github.com/daytonaio/daytona/pkg/profiledata" - "gorm.io/gorm" -) - -type ProfileDataStore struct { - db *gorm.DB -} - -func NewProfileDataStore(db *gorm.DB) (*ProfileDataStore, error) { - err := db.AutoMigrate(&ProfileDataDTO{}) - if err != nil { - return nil, err - } - - return &ProfileDataStore{db: db}, nil -} - -func (p *ProfileDataStore) Get() (*profiledata.ProfileData, error) { - profileDataDTO := ProfileDataDTO{} - tx := p.db.Where("id = ?", ProfileDataId).First(&profileDataDTO) - if tx.Error != nil { - if tx.Error == gorm.ErrRecordNotFound { - return nil, profiledata.ErrProfileDataNotFound - } - return nil, tx.Error - } - - profileData := ToProfileData(profileDataDTO) - - return profileData, nil -} - -func (p *ProfileDataStore) Save(profileData *profiledata.ProfileData) error { - profileDataDTO := ToProfileDataDTO(profileData) - tx := p.db.Save(&profileDataDTO) - if tx.Error != nil { - return tx.Error - } - - return nil -} - -func (p *ProfileDataStore) Delete() error { - tx := p.db.Where("id = ?", ProfileDataId).Delete(&ProfileDataDTO{}) - if tx.Error != nil { - return tx.Error - } - if tx.RowsAffected == 0 { - return profiledata.ErrProfileDataNotFound - } - - return nil -} diff --git a/pkg/db/project_config_store.go b/pkg/db/project_config_store.go deleted file mode 100644 index 40a6295f3f..0000000000 --- a/pkg/db/project_config_store.go +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package db - -import ( - "gorm.io/gorm" - - . "github.com/daytonaio/daytona/pkg/db/dto" - "github.com/daytonaio/daytona/pkg/workspace/project/config" -) - -type ProjectConfigStore struct { - db *gorm.DB -} - -func NewProjectConfigStore(db *gorm.DB) (*ProjectConfigStore, error) { - err := db.AutoMigrate(&ProjectConfigDTO{}) - if err != nil { - return nil, err - } - - return &ProjectConfigStore{db: db}, nil -} - -func (s *ProjectConfigStore) List(filter *config.ProjectConfigFilter) ([]*config.ProjectConfig, error) { - projectConfigsDTOs := []ProjectConfigDTO{} - tx := processProjectConfigFilters(s.db, filter).Find(&projectConfigsDTOs) - - if tx.Error != nil { - return nil, tx.Error - } - - projectConfigs := []*config.ProjectConfig{} - for _, projectConfigDTO := range projectConfigsDTOs { - projectConfigs = append(projectConfigs, ToProjectConfig(projectConfigDTO)) - } - - return projectConfigs, nil -} - -func (s *ProjectConfigStore) Find(filter *config.ProjectConfigFilter) (*config.ProjectConfig, error) { - projectConfigDTO := ProjectConfigDTO{} - tx := processProjectConfigFilters(s.db, filter).First(&projectConfigDTO) - - if tx.Error != nil { - if IsRecordNotFound(tx.Error) { - return nil, config.ErrProjectConfigNotFound - } - return nil, tx.Error - } - - return ToProjectConfig(projectConfigDTO), nil -} - -func (s *ProjectConfigStore) Save(projectConfig *config.ProjectConfig) error { - tx := s.db.Save(ToProjectConfigDTO(projectConfig)) - if tx.Error != nil { - return tx.Error - } - - return nil -} - -func (s *ProjectConfigStore) Delete(projectConfig *config.ProjectConfig) error { - tx := s.db.Delete(ToProjectConfigDTO(projectConfig)) - if tx.Error != nil { - return tx.Error - } - if tx.RowsAffected == 0 { - return config.ErrProjectConfigNotFound - } - - return nil -} - -func processProjectConfigFilters(tx *gorm.DB, filter *config.ProjectConfigFilter) *gorm.DB { - if filter != nil { - if filter.Name != nil { - tx = tx.Where("name = ?", *filter.Name) - } - if filter.Url != nil { - tx = tx.Where("repository_url = ?", *filter.Url) - } - if filter.Default != nil { - tx = tx.Where("is_default = ?", *filter.Default) - } - if filter.GitProviderConfigId != nil { - tx = tx.Where("git_provider_config_id = ?", *filter.GitProviderConfigId) - } - } - - return tx -} diff --git a/pkg/db/provider_target_store.go b/pkg/db/provider_target_store.go deleted file mode 100644 index a0efda39d8..0000000000 --- a/pkg/db/provider_target_store.go +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package db - -import ( - "gorm.io/gorm" - - . "github.com/daytonaio/daytona/pkg/db/dto" - "github.com/daytonaio/daytona/pkg/provider" -) - -type ProviderTargetStore struct { - db *gorm.DB -} - -func NewProviderTargetStore(db *gorm.DB) (*ProviderTargetStore, error) { - err := db.AutoMigrate(&ProviderTargetDTO{}) - if err != nil { - return nil, err - } - - return &ProviderTargetStore{db: db}, nil -} - -func (s *ProviderTargetStore) List(filter *provider.TargetFilter) ([]*provider.ProviderTarget, error) { - targetDTOs := []ProviderTargetDTO{} - tx := processTargetFilters(s.db, filter).Find(&targetDTOs) - - if tx.Error != nil { - return nil, tx.Error - } - - targets := []*provider.ProviderTarget{} - for _, targetDTO := range targetDTOs { - targets = append(targets, ToProviderTarget(targetDTO)) - } - - return targets, nil -} - -func (s *ProviderTargetStore) Find(filter *provider.TargetFilter) (*provider.ProviderTarget, error) { - targetDTO := ProviderTargetDTO{} - tx := processTargetFilters(s.db, filter).First(&targetDTO) - - if tx.Error != nil { - if IsRecordNotFound(tx.Error) { - return nil, provider.ErrTargetNotFound - } - return nil, tx.Error - } - - return ToProviderTarget(targetDTO), nil -} - -func (s *ProviderTargetStore) Save(target *provider.ProviderTarget) error { - tx := s.db.Save(ToProviderTargetDTO(target)) - if tx.Error != nil { - return tx.Error - } - - return nil -} - -func (s *ProviderTargetStore) Delete(target *provider.ProviderTarget) error { - tx := s.db.Delete(ToProviderTargetDTO(target)) - if tx.Error != nil { - return tx.Error - } - if tx.RowsAffected == 0 { - return provider.ErrTargetNotFound - } - - return nil -} - -func processTargetFilters(tx *gorm.DB, filter *provider.TargetFilter) *gorm.DB { - if filter != nil { - if filter.Name != nil { - tx = tx.Where("name = ?", *filter.Name) - } - if filter.Default != nil { - tx = tx.Where("is_default = ?", *filter.Default) - } - } - - return tx -} diff --git a/pkg/db/runner_metadata_store.go b/pkg/db/runner_metadata_store.go new file mode 100644 index 0000000000..a0cc58b946 --- /dev/null +++ b/pkg/db/runner_metadata_store.go @@ -0,0 +1,76 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package db + +import ( + "context" + + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/stores" +) + +type RunnerMetadataStore struct { + IStore +} + +func NewRunnerMetadataStore(store IStore) (stores.RunnerMetadataStore, error) { + err := store.AutoMigrate(&models.RunnerMetadata{}) + if err != nil { + return nil, err + } + + return &RunnerMetadataStore{store}, nil +} + +func (s *RunnerMetadataStore) List(ctx context.Context) ([]*models.RunnerMetadata, error) { + tx := s.GetTransaction(ctx) + + var runnerMetadata []*models.RunnerMetadata + tx = tx.Find(&runnerMetadata) + if tx.Error != nil { + return nil, tx.Error + } + + return runnerMetadata, nil +} + +func (s *RunnerMetadataStore) Find(ctx context.Context, runnerId string) (*models.RunnerMetadata, error) { + tx := s.GetTransaction(ctx) + + runnerMetadata := &models.RunnerMetadata{} + tx = tx.Where("runner_id = ?", runnerId).First(&runnerMetadata) + if tx.Error != nil { + if IsRecordNotFound(tx.Error) { + return nil, stores.ErrRunnerMetadataNotFound + } + return nil, tx.Error + } + + return runnerMetadata, nil +} + +func (s *RunnerMetadataStore) Save(ctx context.Context, runnerMetadata *models.RunnerMetadata) error { + tx := s.GetTransaction(ctx) + + tx = tx.Save(runnerMetadata) + if tx.Error != nil { + return tx.Error + } + + return nil +} + +func (s *RunnerMetadataStore) Delete(ctx context.Context, runnerMetadata *models.RunnerMetadata) error { + tx := s.GetTransaction(ctx) + + tx = tx.Delete(runnerMetadata) + if tx.Error != nil { + return tx.Error + } + if tx.RowsAffected == 0 { + return stores.ErrRunnerMetadataNotFound + } + + return nil +} diff --git a/pkg/db/runner_store.go b/pkg/db/runner_store.go new file mode 100644 index 0000000000..2eb14143f6 --- /dev/null +++ b/pkg/db/runner_store.go @@ -0,0 +1,82 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package db + +import ( + "context" + + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/stores" + "gorm.io/gorm" + "gorm.io/gorm/clause" +) + +type RunnerStore struct { + IStore +} + +func NewRunnerStore(store IStore) (stores.RunnerStore, error) { + err := store.AutoMigrate(&models.Runner{}) + if err != nil { + return nil, err + } + + return &RunnerStore{store}, nil +} + +func (s *RunnerStore) List(ctx context.Context) ([]*models.Runner, error) { + tx := s.GetTransaction(ctx) + + runners := []*models.Runner{} + tx = preloadRunnerEntities(tx).Find(&runners) + if tx.Error != nil { + return nil, tx.Error + } + + return runners, nil +} + +func (s *RunnerStore) Find(ctx context.Context, idOrName string) (*models.Runner, error) { + tx := s.GetTransaction(ctx) + + runner := &models.Runner{} + tx = preloadRunnerEntities(tx).Where("id = ? OR name = ?", idOrName, idOrName).First(runner) + if tx.Error != nil { + if IsRecordNotFound(tx.Error) { + return nil, stores.ErrRunnerNotFound + } + return nil, tx.Error + } + + return runner, nil +} + +func (s *RunnerStore) Save(ctx context.Context, runner *models.Runner) error { + tx := s.GetTransaction(ctx) + + tx = tx.Save(runner) + if tx.Error != nil { + return tx.Error + } + + return nil +} + +func (s *RunnerStore) Delete(ctx context.Context, runner *models.Runner) error { + tx := s.GetTransaction(ctx) + + tx = tx.Delete(runner) + if tx.Error != nil { + return tx.Error + } + if tx.RowsAffected == 0 { + return stores.ErrRunnerNotFound + } + + return nil +} + +func preloadRunnerEntities(tx *gorm.DB) *gorm.DB { + return tx.Preload(clause.Associations) +} diff --git a/pkg/db/target_config_store.go b/pkg/db/target_config_store.go new file mode 100644 index 0000000000..2f379a5f48 --- /dev/null +++ b/pkg/db/target_config_store.go @@ -0,0 +1,74 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package db + +import ( + "context" + + "gorm.io/gorm" + + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/stores" +) + +type TargetConfigStore struct { + IStore +} + +func NewTargetConfigStore(store IStore) (stores.TargetConfigStore, error) { + err := store.AutoMigrate(&models.TargetConfig{}) + if err != nil { + return nil, err + } + + return &TargetConfigStore{store}, nil +} + +func (s *TargetConfigStore) List(ctx context.Context, allowDeleted bool) ([]*models.TargetConfig, error) { + tx := s.GetTransaction(ctx) + + targetConfigs := []*models.TargetConfig{} + tx = processTargetConfigFilters(tx, nil, allowDeleted).Find(&targetConfigs) + + if tx.Error != nil { + return nil, tx.Error + } + + return targetConfigs, nil +} + +func (s *TargetConfigStore) Find(ctx context.Context, idOrName string, allowDeleted bool) (*models.TargetConfig, error) { + tx := s.GetTransaction(ctx) + + targetConfig := &models.TargetConfig{} + tx = processTargetConfigFilters(tx, &idOrName, allowDeleted).First(targetConfig) + + if tx.Error != nil { + if IsRecordNotFound(tx.Error) { + return nil, stores.ErrTargetConfigNotFound + } + return nil, tx.Error + } + + return targetConfig, nil +} + +func (s *TargetConfigStore) Save(ctx context.Context, targetConfig *models.TargetConfig) error { + tx := s.GetTransaction(ctx) + + tx = tx.Save(targetConfig) + return tx.Error +} + +func processTargetConfigFilters(tx *gorm.DB, idOrName *string, allowDeleted bool) *gorm.DB { + if idOrName != nil { + tx = tx.Where("id = ? OR name = ?", *idOrName, *idOrName) + } + + if !allowDeleted { + tx = tx.Where("deleted = ?", false) + } + + return tx +} diff --git a/pkg/db/target_metadata_store.go b/pkg/db/target_metadata_store.go new file mode 100644 index 0000000000..2eb3c46351 --- /dev/null +++ b/pkg/db/target_metadata_store.go @@ -0,0 +1,64 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package db + +import ( + "context" + + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/stores" +) + +type TargetMetadataStore struct { + IStore +} + +func NewTargetMetadataStore(store IStore) (stores.TargetMetadataStore, error) { + err := store.AutoMigrate(&models.TargetMetadata{}) + if err != nil { + return nil, err + } + + return &TargetMetadataStore{store}, nil +} + +func (s *TargetMetadataStore) Find(ctx context.Context, targetId string) (*models.TargetMetadata, error) { + tx := s.GetTransaction(ctx) + + targetMetadata := &models.TargetMetadata{} + tx = tx.Where("target_id = ?", targetId).First(&targetMetadata) + if tx.Error != nil { + if IsRecordNotFound(tx.Error) { + return nil, stores.ErrTargetMetadataNotFound + } + return nil, tx.Error + } + + return targetMetadata, nil +} + +func (s *TargetMetadataStore) Save(ctx context.Context, targetMetadata *models.TargetMetadata) error { + tx := s.GetTransaction(ctx) + + tx = tx.Save(targetMetadata) + if tx.Error != nil { + return tx.Error + } + + return nil +} + +func (s *TargetMetadataStore) Delete(ctx context.Context, targetMetadata *models.TargetMetadata) error { + tx := s.GetTransaction(ctx) + + tx = tx.Delete(targetMetadata) + if tx.Error != nil { + return tx.Error + } + if tx.RowsAffected == 0 { + return stores.ErrTargetMetadataNotFound + } + + return nil +} diff --git a/pkg/db/target_store.go b/pkg/db/target_store.go new file mode 100644 index 0000000000..e5e1a37cd4 --- /dev/null +++ b/pkg/db/target_store.go @@ -0,0 +1,100 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package db + +import ( + "context" + + "gorm.io/gorm" + "gorm.io/gorm/clause" + + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/stores" +) + +type TargetStore struct { + IStore +} + +func NewTargetStore(store IStore) (stores.TargetStore, error) { + err := store.AutoMigrate(&models.Target{}) + if err != nil { + return nil, err + } + + return &TargetStore{store}, nil +} + +func (s *TargetStore) List(ctx context.Context, filter *stores.TargetFilter) ([]*models.Target, error) { + tx := s.GetTransaction(ctx) + + targets := []*models.Target{} + + tx = preloadTargetEntities(processTargetFilters(tx, filter)).Find(&targets) + if tx.Error != nil { + return nil, tx.Error + } + return targets, nil +} + +func (s *TargetStore) Find(ctx context.Context, filter *stores.TargetFilter) (*models.Target, error) { + tx := s.GetTransaction(ctx) + + tg := &models.Target{} + + tx = preloadTargetEntities(processTargetFilters(tx, filter)).First(tg) + if tx.Error != nil { + return nil, tx.Error + } + + if tx.Error != nil { + if IsRecordNotFound(tx.Error) { + return nil, stores.ErrTargetNotFound + } + return nil, tx.Error + } + return tg, nil +} + +func (s *TargetStore) Save(ctx context.Context, target *models.Target) error { + tx := s.GetTransaction(ctx) + + tx = tx.Save(target) + if tx.Error != nil { + return tx.Error + } + + return nil +} + +func (s *TargetStore) Delete(ctx context.Context, t *models.Target) error { + tx := s.GetTransaction(ctx) + + tx = tx.Delete(t) + if tx.Error != nil { + return tx.Error + } + if tx.RowsAffected == 0 { + return stores.ErrTargetNotFound + } + + return nil +} + +func processTargetFilters(tx *gorm.DB, filter *stores.TargetFilter) *gorm.DB { + if filter != nil { + if filter.IdOrName != nil { + tx = tx.Where("id = ? OR name = ?", *filter.IdOrName, *filter.IdOrName) + } + if filter.Default != nil { + tx = tx.Where("is_default = ?", *filter.Default) + } + } + + return tx +} + +func preloadTargetEntities(tx *gorm.DB) *gorm.DB { + return tx.Preload(clause.Associations).Preload("Workspaces.LastJob").Preload("LastJob") +} diff --git a/pkg/db/workspace_metadata_store.go b/pkg/db/workspace_metadata_store.go new file mode 100644 index 0000000000..4fa75102e6 --- /dev/null +++ b/pkg/db/workspace_metadata_store.go @@ -0,0 +1,64 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package db + +import ( + "context" + + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/stores" +) + +type WorkspaceMetadataStore struct { + IStore +} + +func NewWorkspaceMetadataStore(store IStore) (stores.WorkspaceMetadataStore, error) { + err := store.AutoMigrate(&models.WorkspaceMetadata{}) + if err != nil { + return nil, err + } + + return &WorkspaceMetadataStore{store}, nil +} + +func (s *WorkspaceMetadataStore) Find(ctx context.Context, workspaceId string) (*models.WorkspaceMetadata, error) { + tx := s.GetTransaction(ctx) + + workspaceMetadata := &models.WorkspaceMetadata{} + tx = tx.Where("workspace_id = ?", workspaceId).First(&workspaceMetadata) + if tx.Error != nil { + if IsRecordNotFound(tx.Error) { + return nil, stores.ErrWorkspaceMetadataNotFound + } + return nil, tx.Error + } + + return workspaceMetadata, nil +} + +func (s *WorkspaceMetadataStore) Save(ctx context.Context, workspaceMetadata *models.WorkspaceMetadata) error { + tx := s.GetTransaction(ctx) + + tx = tx.Save(workspaceMetadata) + if tx.Error != nil { + return tx.Error + } + + return nil +} + +func (s *WorkspaceMetadataStore) Delete(ctx context.Context, workspaceMetadata *models.WorkspaceMetadata) error { + tx := s.GetTransaction(ctx) + + tx = tx.Delete(workspaceMetadata) + if tx.Error != nil { + return tx.Error + } + if tx.RowsAffected == 0 { + return stores.ErrWorkspaceMetadataNotFound + } + + return nil +} diff --git a/pkg/db/workspace_store.go b/pkg/db/workspace_store.go index 6800df94c2..a27f7a3cd0 100644 --- a/pkg/db/workspace_store.go +++ b/pkg/db/workspace_store.go @@ -4,55 +4,59 @@ package db import ( + "context" + "gorm.io/gorm" + "gorm.io/gorm/clause" - . "github.com/daytonaio/daytona/pkg/db/dto" - "github.com/daytonaio/daytona/pkg/workspace" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/stores" ) type WorkspaceStore struct { - db *gorm.DB + IStore } -func NewWorkspaceStore(db *gorm.DB) (*WorkspaceStore, error) { - err := db.AutoMigrate(&WorkspaceDTO{}) +func NewWorkspaceStore(store IStore) (stores.WorkspaceStore, error) { + err := store.AutoMigrate(&models.Workspace{}) if err != nil { return nil, err } - return &WorkspaceStore{db: db}, nil + return &WorkspaceStore{store}, nil } -func (w *WorkspaceStore) List() ([]*workspace.Workspace, error) { - workspaceDTOs := []WorkspaceDTO{} - tx := w.db.Find(&workspaceDTOs) +func (s *WorkspaceStore) List(ctx context.Context) ([]*models.Workspace, error) { + tx := s.GetTransaction(ctx) + + workspaces := []*models.Workspace{} + tx = preloadWorkspaceEntities(tx).Find(&workspaces) if tx.Error != nil { return nil, tx.Error } - workspaces := []*workspace.Workspace{} - for _, workspaceDTO := range workspaceDTOs { - workspaces = append(workspaces, ToWorkspace(workspaceDTO)) - } - return workspaces, nil } -func (w *WorkspaceStore) Find(idOrName string) (*workspace.Workspace, error) { - workspaceDTO := WorkspaceDTO{} - tx := w.db.Where("id = ? OR name = ?", idOrName, idOrName).First(&workspaceDTO) +func (s *WorkspaceStore) Find(ctx context.Context, idOrName string) (*models.Workspace, error) { + tx := s.GetTransaction(ctx) + + workspace := &models.Workspace{} + tx = preloadWorkspaceEntities(tx).Where("id = ? OR name = ?", idOrName, idOrName).First(workspace) if tx.Error != nil { if IsRecordNotFound(tx.Error) { - return nil, workspace.ErrWorkspaceNotFound + return nil, stores.ErrWorkspaceNotFound } return nil, tx.Error } - return ToWorkspace(workspaceDTO), nil + return workspace, nil } -func (w *WorkspaceStore) Save(workspace *workspace.Workspace) error { - tx := w.db.Save(ToWorkspaceDTO(workspace)) +func (s *WorkspaceStore) Save(ctx context.Context, workspace *models.Workspace) error { + tx := s.GetTransaction(ctx) + + tx = tx.Save(workspace) if tx.Error != nil { return tx.Error } @@ -60,14 +64,20 @@ func (w *WorkspaceStore) Save(workspace *workspace.Workspace) error { return nil } -func (w *WorkspaceStore) Delete(ws *workspace.Workspace) error { - tx := w.db.Delete(ToWorkspaceDTO(ws)) +func (s *WorkspaceStore) Delete(ctx context.Context, workspace *models.Workspace) error { + tx := s.GetTransaction(ctx) + + tx = tx.Delete(workspace) if tx.Error != nil { return tx.Error } if tx.RowsAffected == 0 { - return workspace.ErrWorkspaceNotFound + return stores.ErrWorkspaceNotFound } return nil } + +func preloadWorkspaceEntities(tx *gorm.DB) *gorm.DB { + return tx.Preload(clause.Associations).Preload("Target.TargetConfig").Preload("LastJob") +} diff --git a/pkg/db/workspace_template_store.go b/pkg/db/workspace_template_store.go new file mode 100644 index 0000000000..04acc5e1c3 --- /dev/null +++ b/pkg/db/workspace_template_store.go @@ -0,0 +1,99 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package db + +import ( + "context" + + "gorm.io/gorm" + + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/stores" +) + +type WorkspaceTemplateStore struct { + IStore +} + +func NewWorkspaceTemplateStore(store IStore) (stores.WorkspaceTemplateStore, error) { + err := store.AutoMigrate(&models.WorkspaceTemplate{}) + if err != nil { + return nil, err + } + + return &WorkspaceTemplateStore{store}, nil +} + +func (s *WorkspaceTemplateStore) List(ctx context.Context, filter *stores.WorkspaceTemplateFilter) ([]*models.WorkspaceTemplate, error) { + tx := s.GetTransaction(ctx) + + workspaceTemplates := []*models.WorkspaceTemplate{} + tx = processWorkspaceTemplateFilters(tx, filter).Find(&workspaceTemplates) + + if tx.Error != nil { + return nil, tx.Error + } + + return workspaceTemplates, nil +} + +func (s *WorkspaceTemplateStore) Find(ctx context.Context, filter *stores.WorkspaceTemplateFilter) (*models.WorkspaceTemplate, error) { + tx := s.GetTransaction(ctx) + + workspaceTemplate := &models.WorkspaceTemplate{} + tx = processWorkspaceTemplateFilters(tx, filter).First(workspaceTemplate) + + if tx.Error != nil { + if IsRecordNotFound(tx.Error) { + return nil, stores.ErrWorkspaceTemplateNotFound + } + return nil, tx.Error + } + + return workspaceTemplate, nil +} + +func (s *WorkspaceTemplateStore) Save(ctx context.Context, workspaceTemplate *models.WorkspaceTemplate) error { + tx := s.GetTransaction(ctx) + + tx = tx.Save(workspaceTemplate) + if tx.Error != nil { + return tx.Error + } + + return nil +} + +func (s *WorkspaceTemplateStore) Delete(ctx context.Context, workspaceTemplate *models.WorkspaceTemplate) error { + tx := s.GetTransaction(ctx) + + tx = tx.Delete(workspaceTemplate) + if tx.Error != nil { + return tx.Error + } + if tx.RowsAffected == 0 { + return stores.ErrWorkspaceTemplateNotFound + } + + return nil +} + +func processWorkspaceTemplateFilters(tx *gorm.DB, filter *stores.WorkspaceTemplateFilter) *gorm.DB { + if filter != nil { + if filter.Name != nil { + tx = tx.Where("name = ?", *filter.Name) + } + if filter.Url != nil { + tx = tx.Where("repository_url = ?", *filter.Url) + } + if filter.Default != nil { + tx = tx.Where("is_default = ?", *filter.Default) + } + if filter.GitProviderConfigId != nil { + tx = tx.Where("git_provider_config_id = ?", *filter.GitProviderConfigId) + } + } + + return tx +} diff --git a/pkg/docker/README.md b/pkg/docker/README.md index a83692b38a..19ab403f07 100644 --- a/pkg/docker/README.md +++ b/pkg/docker/README.md @@ -1,13 +1,14 @@ ## Package Purpose -The purpose of the `docker` package is to provide a single library that providers can use to easily create workspaces and projects. -Most providers will import the package and call commands from the `DockerClient` in order to create workspaces and projects on provided targets. +The purpose of the `docker` package is to provide a single library that providers can use to easily create targets and workspaces. +Most providers will import the package and call commands from the `DockerClient` in order to create targets and workspaces on provided targets. ## Usage To use the Daytona `DockerClient`, the consumer of the library must provide a Docker API client from `github.com/docker/docker/client`. Example: + ```golang import ( "github.com/docker/docker/client" @@ -31,12 +32,14 @@ func GetDockerClient() (docker.IDockerClient, error) { To test changes made in this library, other than writing tests, we recommend using the library locally with the [Docker provider](https://github.com/daytonaio/daytona-provider-docker). The procedure would be as follows: + 1. Clone the [Docker provider](https://github.com/daytonaio/daytona-provider-docker) 1. Open the `go.mod` file. 1. Add `replace github.com/daytonaio/daytona => ` 1. Run `go mod tidy` 1. Build the Docker provider and store it to your local provider directory. - - `go build -o /docker-provider/docker-provider main.go` - - If you're developing Daytona in a devcontainer, ` = ~/.config/daytona/providers` + +- `go build -o /docker-provider/docker-provider main.go` +- If you're developing Daytona in a devcontainer, ` = ~/.config/daytona/providers` **Note**: Any change to the `docker` library will require that providers update the version of `github.com/daytonaio/daytona` after the next release and post a release of their own. diff --git a/pkg/docker/client.go b/pkg/docker/client.go index 4ff5e988de..e2718d0a00 100644 --- a/pkg/docker/client.go +++ b/pkg/docker/client.go @@ -8,47 +8,44 @@ import ( "fmt" "io" - "github.com/daytonaio/daytona/pkg/containerregistry" - "github.com/daytonaio/daytona/pkg/gitprovider" + "github.com/daytonaio/daytona/pkg/common" + "github.com/daytonaio/daytona/pkg/models" "github.com/daytonaio/daytona/pkg/ssh" - "github.com/daytonaio/daytona/pkg/workspace" - "github.com/daytonaio/daytona/pkg/workspace/project" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/filters" "github.com/docker/docker/client" ) -type CreateProjectOptions struct { - Project *project.Project - ProjectDir string - ContainerRegistry *containerregistry.ContainerRegistry - LogWriter io.Writer - Gpc *gitprovider.GitProviderConfig - SshClient *ssh.Client - BuilderImage string - BuilderContainerRegistry *containerregistry.ContainerRegistry +type CreateWorkspaceOptions struct { + Workspace *models.Workspace + WorkspaceDir string + ContainerRegistries common.ContainerRegistries + LogWriter io.Writer + Gpc *models.GitProviderConfig + SshClient *ssh.Client + BuilderImage string } type IDockerClient interface { - CreateProject(opts *CreateProjectOptions) error - CreateWorkspace(workspace *workspace.Workspace, workspaceDir string, logWriter io.Writer, sshClient *ssh.Client) error + CreateWorkspace(opts *CreateWorkspaceOptions) error + CreateTarget(target *models.Target, targetDir string, logWriter io.Writer, sshClient *ssh.Client) error - DestroyProject(project *project.Project, projectDir string, sshClient *ssh.Client) error - DestroyWorkspace(workspace *workspace.Workspace, workspaceDir string, sshClient *ssh.Client) error + DestroyWorkspace(workspace *models.Workspace, workspaceDir string, sshClient *ssh.Client) error + DestroyTarget(target *models.Target, targetDir string, sshClient *ssh.Client) error - StartProject(opts *CreateProjectOptions, daytonaDownloadUrl string) error - StopProject(project *project.Project, logWriter io.Writer) error + StartWorkspace(opts *CreateWorkspaceOptions, daytonaDownloadUrl string) error + StopWorkspace(workspace *models.Workspace, logWriter io.Writer) error - GetProjectInfo(project *project.Project) (*project.ProjectInfo, error) - GetWorkspaceInfo(ws *workspace.Workspace) (*workspace.WorkspaceInfo, error) + GetWorkspaceProviderMetadata(workspace *models.Workspace) (string, error) + GetTargetProviderMetadata(t *models.Target) (string, error) - GetProjectContainerName(project *project.Project) string - GetProjectVolumeName(project *project.Project) string + GetWorkspaceContainerName(workspace *models.Workspace) string + GetWorkspaceVolumeName(workspace *models.Workspace) string ExecSync(containerID string, config container.ExecOptions, outputWriter io.Writer) (*ExecResult, error) GetContainerLogs(containerName string, logWriter io.Writer) error - PullImage(imageName string, cr *containerregistry.ContainerRegistry, logWriter io.Writer) error - PushImage(imageName string, cr *containerregistry.ContainerRegistry, logWriter io.Writer) error + PullImage(imageName string, cr *models.ContainerRegistry, logWriter io.Writer) error + PushImage(imageName string, cr *models.ContainerRegistry, logWriter io.Writer) error DeleteImage(imageName string, force bool, logWriter io.Writer) error CreateFromDevcontainer(opts CreateDevcontainerOptions) (string, RemoteUser, error) @@ -69,29 +66,29 @@ type DockerClient struct { apiClient client.APIClient } -func (d *DockerClient) GetProjectContainerName(project *project.Project) string { +func (d *DockerClient) GetWorkspaceContainerName(workspace *models.Workspace) string { containers, err := d.apiClient.ContainerList(context.Background(), container.ListOptions{ - Filters: filters.NewArgs(filters.Arg("label", fmt.Sprintf("daytona.workspace.id=%s", project.WorkspaceId)), filters.Arg("label", fmt.Sprintf("daytona.project.name=%s", project.Name))), + Filters: filters.NewArgs(filters.Arg("label", fmt.Sprintf("daytona.target.id=%s", workspace.TargetId)), filters.Arg("label", fmt.Sprintf("daytona.workspace.id=%s", workspace.Id))), All: true, }) if err != nil || len(containers) == 0 { - return project.WorkspaceId + "-" + project.Name + return workspace.TargetId + "-" + workspace.Id } return containers[0].ID } -func (d *DockerClient) GetProjectVolumeName(project *project.Project) string { - return project.WorkspaceId + "-" + project.Name +func (d *DockerClient) GetWorkspaceVolumeName(workspace *models.Workspace) string { + return workspace.TargetId + "-" + workspace.Id } func (d *DockerClient) getComposeContainers(c types.ContainerJSON) (string, []types.Container, error) { ctx := context.Background() for k, v := range c.Config.Labels { - if k == "com.docker.compose.project" { + if k == "com.docker.compose.workspace" { containers, err := d.apiClient.ContainerList(ctx, container.ListOptions{ - Filters: filters.NewArgs(filters.Arg("label", fmt.Sprintf("com.docker.compose.project=%s", v))), + Filters: filters.NewArgs(filters.Arg("label", fmt.Sprintf("com.docker.compose.workspace=%s", v))), }) return v, containers, err } diff --git a/pkg/docker/client_test.go b/pkg/docker/client_test.go index ac9bdd045b..fd1b4f7865 100644 --- a/pkg/docker/client_test.go +++ b/pkg/docker/client_test.go @@ -9,33 +9,38 @@ import ( "github.com/daytonaio/daytona/internal/testing/docker/mocks" "github.com/daytonaio/daytona/pkg/docker" "github.com/daytonaio/daytona/pkg/gitprovider" - "github.com/daytonaio/daytona/pkg/workspace" - "github.com/daytonaio/daytona/pkg/workspace/project" - "github.com/daytonaio/daytona/pkg/workspace/project/buildconfig" + "github.com/daytonaio/daytona/pkg/models" "github.com/stretchr/testify/suite" ) -var project1 = &project.Project{ +var workspace1 = &models.Workspace{ Name: "test", Repository: &gitprovider.GitRepository{ Id: "123", Url: "https://github.com/daytonaio/daytona", Name: "daytona", }, - BuildConfig: &buildconfig.BuildConfig{}, Image: "test-image:tag", User: "test-user", - WorkspaceId: "123", - Target: "test", + TargetId: "123", + BuildConfig: &models.BuildConfig{}, } -var workspace1 = &workspace.Workspace{ - Id: "123", - Name: "test", - Target: "test", - Projects: []*project.Project{ - project1, +var targetConfig1 = &models.TargetConfig{ + Name: "test", + ProviderInfo: models.ProviderInfo{ + Name: "test-provider", + Version: "test", }, + Options: "test-options", + Deleted: false, +} + +var target1 = &models.Target{ + Id: "123", + Name: "test", + TargetConfigId: targetConfig1.Id, + TargetConfig: *targetConfig1, } type DockerClientTestSuiteConfig struct { diff --git a/pkg/docker/container_logs_test.go b/pkg/docker/container_logs_test.go index 04c2855aba..da50705e09 100644 --- a/pkg/docker/container_logs_test.go +++ b/pkg/docker/container_logs_test.go @@ -17,7 +17,7 @@ import ( func (s *DockerClientTestSuite) TestGetContainerLogs() { s.mockClient.On("ContainerList", mock.Anything, mock.Anything).Return([]types.Container{}, nil) - containerName := s.dockerClient.GetProjectContainerName(project1) + containerName := s.dockerClient.GetWorkspaceContainerName(workspace1) logWriter := io.MultiWriter(&util.DebugLogWriter{}) s.mockClient.On("ContainerInspect", mock.Anything, containerName).Return(types.ContainerJSON{ diff --git a/pkg/docker/create.go b/pkg/docker/create.go index 26fd13c0e4..7b0ddf223d 100644 --- a/pkg/docker/create.go +++ b/pkg/docker/create.go @@ -16,43 +16,44 @@ import ( "github.com/daytonaio/daytona/pkg/build/detect" "github.com/daytonaio/daytona/pkg/git" + "github.com/daytonaio/daytona/pkg/models" "github.com/daytonaio/daytona/pkg/ssh" - "github.com/daytonaio/daytona/pkg/workspace" "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/mount" "github.com/go-git/go-git/v5/plumbing/transport/http" log "github.com/sirupsen/logrus" ) -func (d *DockerClient) CreateWorkspace(workspace *workspace.Workspace, workspaceDir string, logWriter io.Writer, sshClient *ssh.Client) error { +func (d *DockerClient) CreateTarget(target *models.Target, targetDir string, logWriter io.Writer, sshClient *ssh.Client) error { var err error if sshClient == nil { - err = os.MkdirAll(workspaceDir, 0755) + err = os.MkdirAll(targetDir, 0755) } else { - err = sshClient.Exec(fmt.Sprintf("mkdir -p %s", workspaceDir), nil) + err = sshClient.Exec(fmt.Sprintf("mkdir -p %s", targetDir), nil) } return err } -func (d *DockerClient) CreateProject(opts *CreateProjectOptions) error { - // pulledImages map keeps track of pulled images for project creation in order to avoid pulling the same image multiple times +func (d *DockerClient) CreateWorkspace(opts *CreateWorkspaceOptions) error { + // pulledImages map keeps track of pulled images for workspace creation in order to avoid pulling the same image multiple times // This is only an optimisation for images with tag 'latest' pulledImages := map[string]bool{} - if opts.Project.BuildConfig != nil { - err := d.PullImage(opts.BuilderImage, opts.BuilderContainerRegistry, opts.LogWriter) + if opts.Workspace.BuildConfig != nil { + cr := opts.ContainerRegistries.FindContainerRegistryByImageName(opts.BuilderImage) + err := d.PullImage(opts.BuilderImage, cr, opts.LogWriter) if err != nil { return err } pulledImages[opts.BuilderImage] = true - err = d.cloneProjectRepository(opts) + err = d.cloneWorkspaceRepository(opts) if err != nil { return err } - builderType, err := detect.DetectProjectBuilderType(opts.Project.BuildConfig, opts.ProjectDir, opts.SshClient) + builderType, err := detect.DetectWorkspaceBuilderType(opts.Workspace.BuildConfig, opts.WorkspaceDir, opts.SshClient) if err != nil { return err } @@ -62,25 +63,25 @@ func (d *DockerClient) CreateProject(opts *CreateProjectOptions) error { _, _, err := d.CreateFromDevcontainer(d.toCreateDevcontainerOptions(opts, true)) return err case detect.BuilderTypeImage: - return d.createProjectFromImage(opts, pulledImages, true) + return d.createWorkspaceFromImage(opts, pulledImages, true) default: return fmt.Errorf("unknown builder type: %s", builderType) } } - return d.createProjectFromImage(opts, pulledImages, false) + return d.createWorkspaceFromImage(opts, pulledImages, false) } -func (d *DockerClient) cloneProjectRepository(opts *CreateProjectOptions) error { +func (d *DockerClient) cloneWorkspaceRepository(opts *CreateWorkspaceOptions) error { ctx := context.Background() if opts.SshClient != nil { - err := opts.SshClient.Exec(fmt.Sprintf("mkdir -p %s", opts.ProjectDir), nil) + err := opts.SshClient.Exec(fmt.Sprintf("mkdir -p %s", opts.WorkspaceDir), nil) if err != nil { return err } } else { - err := os.MkdirAll(opts.ProjectDir, 0755) + err := os.MkdirAll(opts.WorkspaceDir, 0755) if err != nil { return err } @@ -95,10 +96,10 @@ func (d *DockerClient) cloneProjectRepository(opts *CreateProjectOptions) error } gitService := git.Service{ - ProjectDir: fmt.Sprintf("/workdir/%s-%s", opts.Project.WorkspaceId, opts.Project.Name), + WorkspaceDir: fmt.Sprintf("/workdir/%s", opts.Workspace.WorkspaceFolderName()), } - cloneCmd := gitService.CloneRepositoryCmd(opts.Project.Repository, auth) + cloneCmd := gitService.CloneRepositoryCmd(opts.Workspace.Repository, auth) c, err := d.apiClient.ContainerCreate(ctx, &container.Config{ Image: opts.BuilderImage, @@ -111,11 +112,11 @@ func (d *DockerClient) cloneProjectRepository(opts *CreateProjectOptions) error Mounts: []mount.Mount{ { Type: mount.TypeBind, - Source: filepath.Dir(opts.ProjectDir), + Source: filepath.Dir(opts.WorkspaceDir), Target: "/workdir", }, }, - }, nil, nil, fmt.Sprintf("git-clone-%s-%s", opts.Project.WorkspaceId, opts.Project.Name)) + }, nil, nil, fmt.Sprintf("git-clone-%s-%s", opts.Workspace.TargetId, opts.Workspace.Name)) if err != nil { return err } @@ -158,7 +159,7 @@ func (d *DockerClient) cloneProjectRepository(opts *CreateProjectOptions) error return nil } -func (d *DockerClient) updateContainerUserUidGid(containerId string, opts *CreateProjectOptions) (string, error) { +func (d *DockerClient) updateContainerUserUidGid(containerId string, opts *CreateWorkspaceOptions) (string, error) { currentUser, err := user.Current() if err != nil { return "", err @@ -200,20 +201,19 @@ func (d *DockerClient) updateContainerUserUidGid(containerId string, opts *Creat return containerUser, nil } -func (d *DockerClient) toCreateDevcontainerOptions(opts *CreateProjectOptions, prebuild bool) CreateDevcontainerOptions { +func (d *DockerClient) toCreateDevcontainerOptions(opts *CreateWorkspaceOptions, prebuild bool) CreateDevcontainerOptions { return CreateDevcontainerOptions{ - ProjectDir: opts.ProjectDir, - ProjectName: opts.Project.Name, - BuildConfig: opts.Project.BuildConfig, - LogWriter: opts.LogWriter, - SshClient: opts.SshClient, - ContainerRegistry: opts.ContainerRegistry, - BuilderImage: opts.BuilderImage, - BuilderContainerRegistry: opts.BuilderContainerRegistry, - EnvVars: opts.Project.EnvVars, + WorkspaceDir: opts.WorkspaceDir, + WorkspaceFolderName: opts.Workspace.WorkspaceFolderName(), + BuildConfig: opts.Workspace.BuildConfig, + LogWriter: opts.LogWriter, + SshClient: opts.SshClient, + ContainerRegistries: opts.ContainerRegistries, + BuilderImage: opts.BuilderImage, + EnvVars: opts.Workspace.EnvVars, IdLabels: map[string]string{ - "daytona.workspace.id": opts.Project.WorkspaceId, - "daytona.project.name": opts.Project.Name, + "daytona.target.id": opts.Workspace.TargetId, + "daytona.workspace.id": opts.Workspace.Id, }, Prebuild: prebuild, } diff --git a/pkg/docker/create_devcontainer.go b/pkg/docker/create_devcontainer.go index 6053aa8e30..f2faf0539c 100644 --- a/pkg/docker/create_devcontainer.go +++ b/pkg/docker/create_devcontainer.go @@ -19,9 +19,9 @@ import ( "github.com/compose-spec/compose-go/v2/cli" "github.com/daytonaio/daytona/internal/util" "github.com/daytonaio/daytona/pkg/build/devcontainer" - "github.com/daytonaio/daytona/pkg/containerregistry" + "github.com/daytonaio/daytona/pkg/common" + "github.com/daytonaio/daytona/pkg/models" "github.com/daytonaio/daytona/pkg/ssh" - "github.com/daytonaio/daytona/pkg/workspace/project/buildconfig" "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/filters" "github.com/docker/docker/api/types/mount" @@ -35,47 +35,47 @@ type RemoteUser string type DevcontainerPaths struct { OverridesDir string OverridesTarget string - ProjectTarget string + WorkspaceDirTarget string TargetConfigFilePath string } type CreateDevcontainerOptions struct { - ProjectDir string + WorkspaceDir string // Name of the project inside the devcontainer - ProjectName string - BuildConfig *buildconfig.BuildConfig - LogWriter io.Writer - SshClient *ssh.Client - ContainerRegistry *containerregistry.ContainerRegistry - Prebuild bool - EnvVars map[string]string - IdLabels map[string]string - BuilderImage string - BuilderContainerRegistry *containerregistry.ContainerRegistry + WorkspaceFolderName string + BuildConfig *models.BuildConfig + LogWriter io.Writer + SshClient *ssh.Client + ContainerRegistries common.ContainerRegistries + Prebuild bool + EnvVars map[string]string + IdLabels map[string]string + BuilderImage string } func (d *DockerClient) CreateFromDevcontainer(opts CreateDevcontainerOptions) (string, RemoteUser, error) { // Ensure that the devcontainer config exists if opts.SshClient != nil { - _, err := opts.SshClient.ReadFile(path.Join(opts.ProjectDir, opts.BuildConfig.Devcontainer.FilePath)) + _, err := opts.SshClient.ReadFile(path.Join(opts.WorkspaceDir, opts.BuildConfig.Devcontainer.FilePath)) if err != nil { return "", "", err } } else { - _, err := os.Stat(filepath.Join(opts.ProjectDir, opts.BuildConfig.Devcontainer.FilePath)) + _, err := os.Stat(filepath.Join(opts.WorkspaceDir, opts.BuildConfig.Devcontainer.FilePath)) if err != nil { return "", "", err } } - socketForwardId, err := d.ensureDockerSockForward(opts.BuilderImage, opts.BuilderContainerRegistry, opts.LogWriter) + cr := opts.ContainerRegistries.FindContainerRegistryByImageName(opts.BuilderImage) + socketForwardId, err := d.ensureDockerSockForward(opts.BuilderImage, cr, opts.LogWriter) if err != nil { return "", "", err } ctx := context.Background() - paths := d.getDevcontainerPaths(opts.ProjectDir, opts.BuildConfig.Devcontainer.FilePath) + paths := d.getDevcontainerPaths(opts.WorkspaceDir, opts.BuildConfig.Devcontainer.FilePath) if opts.SshClient != nil { err = opts.SshClient.Exec(fmt.Sprintf("mkdir -p %s", paths.OverridesDir), opts.LogWriter) @@ -95,7 +95,7 @@ func (d *DockerClient) CreateFromDevcontainer(opts CreateDevcontainerOptions) (s } if opts.Prebuild { - err = d.runInitializeCommand(opts.ProjectDir, config.MergedConfiguration.InitializeCommand, opts.LogWriter, opts.SshClient) + err = d.runInitializeCommand(opts.WorkspaceDir, config.MergedConfiguration.InitializeCommand, opts.LogWriter, opts.SshClient) if err != nil { return "", "", err } @@ -134,12 +134,12 @@ func (d *DockerClient) CreateFromDevcontainer(opts CreateDevcontainerOptions) (s envVars[k] = v } - // If the workspaceFolder is not set in the devcontainer.json, we set it to /workspaces/ + // If the workspaceFolder is not set in the devcontainer.json, we set it to /workspaces/ if _, ok := devcontainerConfig["workspaceFolder"].(string); !ok { - workspaceFolder = fmt.Sprintf("/workspaces/%s", opts.ProjectName) + workspaceFolder = fmt.Sprintf("/workspaces/%s", opts.WorkspaceFolderName) devcontainerConfig["workspaceFolder"] = workspaceFolder } - devcontainerConfig["workspaceMount"] = fmt.Sprintf("source=%s,target=%s,type=bind", opts.ProjectDir, workspaceFolder) + devcontainerConfig["workspaceMount"] = fmt.Sprintf("source=%s,target=%s,type=bind", opts.WorkspaceDir, workspaceFolder) delete(devcontainerConfig, "initializeCommand") @@ -148,7 +148,7 @@ func (d *DockerClient) CreateFromDevcontainer(opts CreateDevcontainerOptions) (s getComposeFilePath := func(composeFilePath string) (string, error) { if opts.SshClient != nil { - composeFilePath = path.Join(paths.ProjectTarget, filepath.Dir(opts.BuildConfig.Devcontainer.FilePath), composeFilePath) + composeFilePath = path.Join(opts.WorkspaceDir, filepath.Dir(opts.BuildConfig.Devcontainer.FilePath), composeFilePath) composeFileContent, err := d.getRemoteComposeContent(&opts, paths, socketForwardId, composeFilePath) if err != nil { @@ -161,7 +161,7 @@ func (d *DockerClient) CreateFromDevcontainer(opts CreateDevcontainerOptions) (s return "", err } } else { - composeFilePath = filepath.Join(opts.ProjectDir, filepath.Dir(opts.BuildConfig.Devcontainer.FilePath), composeFilePath) + composeFilePath = filepath.Join(opts.WorkspaceDir, filepath.Dir(opts.BuildConfig.Devcontainer.FilePath), composeFilePath) } return composeFilePath, nil @@ -202,17 +202,17 @@ func (d *DockerClient) CreateFromDevcontainer(opts CreateDevcontainerOptions) (s return "", "", err } - project.Name = fmt.Sprintf("%s-%s", opts.ProjectName, util.Hash(opts.ProjectDir)) + project.Name = fmt.Sprintf("%s-%s", opts.WorkspaceFolderName, util.Hash(opts.WorkspaceDir)) for _, service := range project.Services { if service.Build != nil { - if strings.HasPrefix(service.Build.Context, opts.ProjectDir) { - service.Build.Context = strings.Replace(service.Build.Context, opts.ProjectDir, paths.ProjectTarget, 1) + if strings.HasPrefix(service.Build.Context, opts.WorkspaceDir) { + service.Build.Context = strings.Replace(service.Build.Context, opts.WorkspaceDir, paths.WorkspaceDirTarget, 1) } } for i, v := range service.Volumes { - if strings.HasPrefix(v.Source, paths.ProjectTarget) { - service.Volumes[i].Source = strings.Replace(v.Source, paths.ProjectTarget, opts.ProjectDir, 1) + if strings.HasPrefix(v.Source, paths.WorkspaceDirTarget) { + service.Volumes[i].Source = strings.Replace(v.Source, paths.WorkspaceDirTarget, opts.WorkspaceDir, 1) } } } @@ -243,7 +243,7 @@ func (d *DockerClient) CreateFromDevcontainer(opts CreateDevcontainerOptions) (s devcontainerConfig["dockerComposeFile"] = path.Join(paths.OverridesTarget, "daytona-compose-override.yml") } - envVars["DAYTONA_PROJECT_DIR"] = workspaceFolder + envVars["DAYTONA_WORKSPACE_DIR"] = workspaceFolder devcontainerConfig["containerEnv"] = envVars @@ -268,7 +268,7 @@ func (d *DockerClient) CreateFromDevcontainer(opts CreateDevcontainerOptions) (s devcontainerCmd := []string{ "devcontainer", "up", - "--workspace-folder=" + paths.ProjectTarget, + "--workspace-folder=" + paths.WorkspaceDirTarget, "--config=" + paths.TargetConfigFilePath, "--override-config=" + path.Join(paths.OverridesTarget, "devcontainer.json"), "--skip-non-blocking-commands", @@ -279,7 +279,8 @@ func (d *DockerClient) CreateFromDevcontainer(opts CreateDevcontainerOptions) (s } if opts.BuildConfig.CachedBuild != nil { - err := d.PullImage(opts.BuildConfig.CachedBuild.Image, opts.ContainerRegistry, opts.LogWriter) + cr := opts.ContainerRegistries.FindContainerRegistryByImageName(opts.BuildConfig.CachedBuild.Image) + err := d.PullImage(opts.BuildConfig.CachedBuild.Image, cr, opts.LogWriter) if err != nil { opts.LogWriter.Write([]byte(fmt.Sprintf("Error pulling cached build image: %v. Continuing without cache.\n", err))) } @@ -292,7 +293,7 @@ func (d *DockerClient) CreateFromDevcontainer(opts CreateDevcontainerOptions) (s devcontainerCmd = append(devcontainerCmd, "--prebuild") } - output, err := d.execDevcontainerCommand(strings.Join(devcontainerCmd, " "), &opts, paths, paths.ProjectTarget, socketForwardId, true, []mount.Mount{ + output, err := d.execDevcontainerCommand(strings.Join(devcontainerCmd, " "), &opts, paths, paths.WorkspaceDirTarget, socketForwardId, true, []mount.Mount{ { Type: mount.TypeBind, Source: paths.OverridesDir, @@ -323,7 +324,7 @@ func (d *DockerClient) CreateFromDevcontainer(opts CreateDevcontainerOptions) (s return result.ContainerId, RemoteUser(result.RemoteUser), nil } -func (d *DockerClient) ensureDockerSockForward(builderImage string, builderContainerRegistry *containerregistry.ContainerRegistry, logWriter io.Writer) (string, error) { +func (d *DockerClient) ensureDockerSockForward(builderImage string, builderContainerRegistry *models.ContainerRegistry, logWriter io.Writer) (string, error) { ctx := context.Background() containers, err := d.apiClient.ContainerList(ctx, container.ListOptions{ @@ -383,7 +384,7 @@ func (d *DockerClient) readDevcontainerConfig(opts *CreateDevcontainerOptions, p // We need to override localEnvs to the host env variables // FIXME: This will not work for features that require localEnv - configEnvOverride, err := d.execDevcontainerCommand(strings.Join(cmd, " "), opts, paths, paths.ProjectTarget, socketForwardId, false, nil) + configEnvOverride, err := d.execDevcontainerCommand(strings.Join(cmd, " "), opts, paths, paths.WorkspaceDirTarget, socketForwardId, false, nil) if err != nil { return "", nil, err } @@ -413,7 +414,7 @@ func (d *DockerClient) readDevcontainerConfig(opts *CreateDevcontainerOptions, p devcontainerCmd := append([]string{}, []string{ "devcontainer", "read-configuration", - "--workspace-folder=" + paths.ProjectTarget, + "--workspace-folder=" + paths.WorkspaceDirTarget, "--config=" + paths.TargetConfigFilePath, "--override-config=" + path.Join(paths.OverridesTarget, "devcontainer.json"), "--include-merged-configuration", @@ -422,7 +423,7 @@ func (d *DockerClient) readDevcontainerConfig(opts *CreateDevcontainerOptions, p "1", }...) - output, err := d.execDevcontainerCommand(strings.Join(devcontainerCmd, " "), opts, paths, paths.ProjectTarget, socketForwardId, false, []mount.Mount{ + output, err := d.execDevcontainerCommand(strings.Join(devcontainerCmd, " "), opts, paths, paths.WorkspaceDirTarget, socketForwardId, false, []mount.Mount{ { Type: mount.TypeBind, Source: paths.OverridesDir, @@ -526,8 +527,8 @@ func (d *DockerClient) execDevcontainerCommand(cmd string, opts *CreateDevcontai mounts := []mount.Mount{ { Type: mount.TypeBind, - Source: opts.ProjectDir, - Target: paths.ProjectTarget, + Source: opts.WorkspaceDir, + Target: paths.WorkspaceDirTarget, }, } @@ -618,17 +619,17 @@ func (d *DockerClient) getRemoteComposeContent(opts *CreateDevcontainerOptions, return output[nameIndex:], nil } -func (d *DockerClient) getDevcontainerPaths(projectDir string, devcontainerFilePath string) DevcontainerPaths { - projectTarget := path.Join("/project", filepath.Base(projectDir)) - targetConfigFilePath := path.Join(projectTarget, devcontainerFilePath) +func (d *DockerClient) getDevcontainerPaths(workspaceDir string, devcontainerFilePath string) DevcontainerPaths { + workspaceDirTarget := path.Join("/project", filepath.Base(workspaceDir)) + targetConfigFilePath := path.Join(workspaceDirTarget, devcontainerFilePath) - overridesDir := filepath.Join(filepath.Dir(projectDir), fmt.Sprintf("%s-data", filepath.Base(projectDir))) + overridesDir := filepath.Join(filepath.Dir(workspaceDir), fmt.Sprintf("%s-data", filepath.Base(workspaceDir))) overridesTarget := "/tmp/overrides" return DevcontainerPaths{ OverridesDir: overridesDir, OverridesTarget: overridesTarget, - ProjectTarget: projectTarget, + WorkspaceDirTarget: workspaceDirTarget, TargetConfigFilePath: targetConfigFilePath, } } diff --git a/pkg/docker/create_image.go b/pkg/docker/create_image.go index 42a21012be..6bc1170570 100644 --- a/pkg/docker/create_image.go +++ b/pkg/docker/create_image.go @@ -9,46 +9,48 @@ import ( "runtime" "time" + "github.com/daytonaio/daytona/pkg/common" + "github.com/daytonaio/daytona/pkg/models" "github.com/daytonaio/daytona/pkg/ports" - "github.com/daytonaio/daytona/pkg/workspace/project" "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/mount" "github.com/docker/go-connections/nat" log "github.com/sirupsen/logrus" ) -// pulledImages map keeps track of pulled images for project creation in order to avoid pulling the same image multiple times +// pulledImages map keeps track of pulled images for workspace creation in order to avoid pulling the same image multiple times // This is only an optimisation for images with tag 'latest' -func (d *DockerClient) createProjectFromImage(opts *CreateProjectOptions, pulledImages map[string]bool, mountProjectDir bool) error { - if pulledImages[opts.Project.Image] { - return d.initProjectContainer(opts, mountProjectDir) +func (d *DockerClient) createWorkspaceFromImage(opts *CreateWorkspaceOptions, pulledImages map[string]bool, mountWorkspaceDir bool) error { + if pulledImages[opts.Workspace.Image] { + return d.initWorkspaceContainer(opts, mountWorkspaceDir) } - err := d.PullImage(opts.Project.Image, opts.ContainerRegistry, opts.LogWriter) + cr := opts.ContainerRegistries.FindContainerRegistryByImageName(opts.Workspace.Image) + err := d.PullImage(opts.Workspace.Image, cr, opts.LogWriter) if err != nil { return err } - pulledImages[opts.Project.Image] = true + pulledImages[opts.Workspace.Image] = true - return d.initProjectContainer(opts, mountProjectDir) + return d.initWorkspaceContainer(opts, mountWorkspaceDir) } -func (d *DockerClient) initProjectContainer(opts *CreateProjectOptions, mountProjectDir bool) error { +func (d *DockerClient) initWorkspaceContainer(opts *CreateWorkspaceOptions, mountWorkspaceDir bool) error { ctx := context.Background() mounts := []mount.Mount{} - if mountProjectDir { + if mountWorkspaceDir { mounts = append(mounts, mount.Mount{ Type: mount.TypeBind, - Source: opts.ProjectDir, - Target: fmt.Sprintf("/home/%s/%s", opts.Project.User, opts.Project.Name), + Source: opts.WorkspaceDir, + Target: fmt.Sprintf("/home/%s/%s", opts.Workspace.User, opts.Workspace.WorkspaceFolderName()), }) } var availablePort *uint16 var portBindings map[nat.Port][]nat.PortBinding - if opts.Project.Target == "local" { + if common.IsLocalDockerTarget(opts.Workspace.Target.TargetConfig.ProviderInfo.Name, opts.Workspace.Target.TargetConfig.Options, opts.Workspace.Target.TargetConfig.ProviderInfo.RunnerId) { p, err := ports.GetAvailableEphemeralPort() if err != nil { log.Error(err) @@ -64,14 +66,14 @@ func (d *DockerClient) initProjectContainer(opts *CreateProjectOptions, mountPro } } - c, err := d.apiClient.ContainerCreate(ctx, GetContainerCreateConfig(opts.Project, availablePort), &container.HostConfig{ + c, err := d.apiClient.ContainerCreate(ctx, GetContainerCreateConfig(opts.Workspace, availablePort), &container.HostConfig{ Privileged: true, Mounts: mounts, ExtraHosts: []string{ "host.docker.internal:host-gateway", }, PortBindings: portBindings, - }, nil, nil, d.GetProjectContainerName(opts.Project)) + }, nil, nil, d.GetWorkspaceContainerName(opts.Workspace)) if err != nil { return err } @@ -92,7 +94,7 @@ func (d *DockerClient) initProjectContainer(opts *CreateProjectOptions, mountPro } }() - if runtime.GOOS != "windows" && mountProjectDir { + if runtime.GOOS != "windows" && mountWorkspaceDir { _, err = d.updateContainerUserUidGid(c.ID, opts) } @@ -106,17 +108,17 @@ func (d *DockerClient) initProjectContainer(opts *CreateProjectOptions, mountPro return nil } -func GetContainerCreateConfig(project *project.Project, toolboxApiHostPort *uint16) *container.Config { +func GetContainerCreateConfig(workspace *models.Workspace, toolboxApiHostPort *uint16) *container.Config { envVars := []string{} - for key, value := range project.EnvVars { + for key, value := range workspace.EnvVars { envVars = append(envVars, fmt.Sprintf("%s=%s", key, value)) } labels := map[string]string{ - "daytona.workspace.id": project.WorkspaceId, - "daytona.workspace.project.name": project.Name, - "daytona.workspace.project.repository.url": project.Repository.Url, + "daytona.target.id": workspace.TargetId, + "daytona.workspace.id": workspace.Id, + "daytona.workspace.repository.url": workspace.Repository.Url, } if toolboxApiHostPort != nil { @@ -129,10 +131,10 @@ func GetContainerCreateConfig(project *project.Project, toolboxApiHostPort *uint } return &container.Config{ - Hostname: project.Name, - Image: project.Image, + Hostname: workspace.Id, + Image: workspace.Image, Labels: labels, - User: project.User, + User: workspace.User, Env: envVars, Entrypoint: []string{"sleep", "infinity"}, AttachStdout: true, diff --git a/pkg/docker/create_test.go b/pkg/docker/create_test.go index 5e1e210de7..7122c97713 100644 --- a/pkg/docker/create_test.go +++ b/pkg/docker/create_test.go @@ -23,33 +23,33 @@ import ( "github.com/stretchr/testify/require" ) -func (s *DockerClientTestSuite) TestCreateWorkspace() { - workspaceDir := s.T().TempDir() +func (s *DockerClientTestSuite) TestCreateTarget() { + targetDir := s.T().TempDir() - err := s.dockerClient.CreateWorkspace(workspace1, workspaceDir, nil, nil) + err := s.dockerClient.CreateTarget(target1, targetDir, nil, nil) require.Nil(s.T(), err) - _, err = os.Stat(workspaceDir) + _, err = os.Stat(targetDir) require.Nil(s.T(), err) } -func (s *DockerClientTestSuite) TestCreateProject() { +func (s *DockerClientTestSuite) TestCreateWorkspace() { s.mockClient.On("ContainerList", mock.Anything, mock.Anything).Return([]types.Container{}, nil) var networkingConfig *network.NetworkingConfig var platform *v1.Platform - projectDir := os.TempDir() + workspaceDir := os.TempDir() - containerName := s.dockerClient.GetProjectContainerName(project1) + containerName := s.dockerClient.GetWorkspaceContainerName(workspace1) s.mockClient.On("ImageList", mock.Anything, image.ListOptions{ - Filters: filters.NewArgs(filters.Arg("reference", project1.Image)), + Filters: filters.NewArgs(filters.Arg("reference", workspace1.Image)), }, ).Return([]image.Summary{}, nil) - s.mockClient.On("ImagePull", mock.Anything, project1.Image, mock.Anything).Return(t_docker.NewPipeReader(""), nil) + s.mockClient.On("ImagePull", mock.Anything, workspace1.Image, mock.Anything).Return(t_docker.NewPipeReader(""), nil) s.mockClient.On("ImagePull", mock.Anything, "daytonaio/workspace-project", mock.Anything).Return(t_docker.NewPipeReader(""), nil) s.mockClient.On("ContainerRemove", mock.Anything, mock.Anything, container.RemoveOptions{RemoveVolumes: true, Force: true}).Return(nil) @@ -76,13 +76,13 @@ func (s *DockerClientTestSuite) TestCreateProject() { Mounts: []mount.Mount{ { Type: mount.TypeBind, - Source: filepath.Dir(projectDir), + Source: filepath.Dir(workspaceDir), Target: "/workdir", }, }, - }, networkingConfig, platform, fmt.Sprintf("git-clone-%s-%s", project1.WorkspaceId, project1.Name), + }, networkingConfig, platform, fmt.Sprintf("git-clone-%s-%s", workspace1.TargetId, workspace1.Name), ).Return(container.CreateResponse{ID: "123"}, nil) - s.mockClient.On("ContainerCreate", mock.Anything, docker.GetContainerCreateConfig(project1, nil), + s.mockClient.On("ContainerCreate", mock.Anything, docker.GetContainerCreateConfig(workspace1, nil), &container.HostConfig{ Privileged: true, ExtraHosts: []string{ @@ -91,8 +91,8 @@ func (s *DockerClientTestSuite) TestCreateProject() { Mounts: []mount.Mount{ { Type: mount.TypeBind, - Source: projectDir, - Target: fmt.Sprintf("/home/%s/%s", project1.User, project1.Name), + Source: workspaceDir, + Target: fmt.Sprintf("/home/%s/%s", workspace1.User, workspace1.Repository.Name), }, }, }, @@ -101,14 +101,14 @@ func (s *DockerClientTestSuite) TestCreateProject() { containerName, ).Return(container.CreateResponse{ID: "123"}, nil) - err := s.dockerClient.CreateProject(&docker.CreateProjectOptions{ - Project: project1, - ProjectDir: projectDir, - ContainerRegistry: nil, - LogWriter: nil, - Gpc: nil, - SshClient: nil, - BuilderImage: "daytonaio/workspace-project", + err := s.dockerClient.CreateWorkspace(&docker.CreateWorkspaceOptions{ + Workspace: workspace1, + WorkspaceDir: workspaceDir, + ContainerRegistries: nil, + LogWriter: nil, + Gpc: nil, + SshClient: nil, + BuilderImage: "daytonaio/workspace-project", }) require.Nil(s.T(), err) } diff --git a/pkg/docker/credential_helper.go b/pkg/docker/credential_helper.go new file mode 100644 index 0000000000..2dcfe303e8 --- /dev/null +++ b/pkg/docker/credential_helper.go @@ -0,0 +1,97 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package docker + +import ( + "encoding/json" + "io" + "os" + "path/filepath" + "strings" +) + +type IDockerCredHelper interface { + SetDockerConfig() error +} + +type DockerCredHelper struct { + DockerConfigFileName string + LogWriter io.Writer + HomeDir string +} + +func (d *DockerCredHelper) SetDockerConfig() error { + err := d.createDockerCredHelperExecutable() + if err != nil { + return err + } + + dockerFilePath := strings.TrimSuffix(d.DockerConfigFileName, "/config.json") + _, err = os.Stat(dockerFilePath) + if err != nil && os.IsNotExist(err) { + err := os.MkdirAll(dockerFilePath, 0755) + if err != nil { + return err + } + } + + _, err = os.Stat(d.DockerConfigFileName) + if err != nil && os.IsNotExist(err) { + _, err := os.Create(d.DockerConfigFileName) + if err != nil { + return err + } + } + + var dockerConfigContent []byte + dockerConfigContent, err = os.ReadFile(d.DockerConfigFileName) + if err != nil || len(dockerConfigContent) == 0 { + dockerConfigContent = []byte("{}") + } + + var cfg map[string]interface{} + if err := json.Unmarshal(dockerConfigContent, &cfg); err != nil { + return err + } + + cfg["credsStore"] = "daytona" + + updatedConfigContent, err := json.MarshalIndent(cfg, "", " ") + if err != nil { + return err + } + + return os.WriteFile(d.DockerConfigFileName, updatedConfigContent, 0755) +} + +func (d *DockerCredHelper) createDockerCredHelperExecutable() error { + content := "#!/bin/bash\ndaytona docker-cred\n" + fileName := "docker-credential-daytona" + filePath := "/usr/local/bin" + + _, err := os.Create(filepath.Join(filePath, fileName)) + if err != nil { + filePath = filepath.Join(d.HomeDir, ".local", "bin") + + _, ok := os.Stat(filePath) + if os.IsNotExist(ok) { + err := os.MkdirAll(filePath, 0755) + if err != nil { + return err + } + } + + _, err = os.Create(filepath.Join(filePath, fileName)) + if err != nil { + return err + } + } + + err = os.WriteFile(filepath.Join(filePath, fileName), []byte(content), 0755) + if err != nil { + return err + } + + return os.Chmod(filepath.Join(filePath, fileName), 0755) +} diff --git a/pkg/docker/destroy.go b/pkg/docker/destroy.go index 59e1de6011..e930e77aa9 100644 --- a/pkg/docker/destroy.go +++ b/pkg/docker/destroy.go @@ -8,38 +8,37 @@ import ( "fmt" "os" + "github.com/daytonaio/daytona/pkg/models" "github.com/daytonaio/daytona/pkg/ssh" - "github.com/daytonaio/daytona/pkg/workspace" - "github.com/daytonaio/daytona/pkg/workspace/project" "github.com/docker/docker/api/types/container" "github.com/docker/docker/client" ) -func (d *DockerClient) DestroyWorkspace(workspace *workspace.Workspace, workspaceDir string, sshClient *ssh.Client) error { +func (d *DockerClient) DestroyTarget(target *models.Target, targetDir string, sshClient *ssh.Client) error { if sshClient == nil { - return os.RemoveAll(workspaceDir) + return os.RemoveAll(targetDir) } else { - return sshClient.Exec(fmt.Sprintf("rm -rf %s", workspaceDir), nil) + return sshClient.Exec(fmt.Sprintf("rm -rf %s", targetDir), nil) } } -func (d *DockerClient) DestroyProject(project *project.Project, projectDir string, sshClient *ssh.Client) error { - err := d.removeProjectContainer(project) +func (d *DockerClient) DestroyWorkspace(workspace *models.Workspace, workspaceDir string, sshClient *ssh.Client) error { + err := d.removeWorkspaceContainer(workspace) if err != nil { return err } if sshClient == nil { - return os.RemoveAll(projectDir) + return os.RemoveAll(workspaceDir) } else { - return sshClient.Exec(fmt.Sprintf("rm -rf %s", projectDir), nil) + return sshClient.Exec(fmt.Sprintf("rm -rf %s", workspaceDir), nil) } } -func (d *DockerClient) removeProjectContainer(p *project.Project) error { +func (d *DockerClient) removeWorkspaceContainer(w *models.Workspace) error { ctx := context.Background() - containerName := d.GetProjectContainerName(p) + containerName := d.GetWorkspaceContainerName(w) c, err := d.apiClient.ContainerInspect(ctx, containerName) if err != nil { diff --git a/pkg/docker/destroy_test.go b/pkg/docker/destroy_test.go index 11e6cc3d93..594eb6621d 100644 --- a/pkg/docker/destroy_test.go +++ b/pkg/docker/destroy_test.go @@ -12,20 +12,20 @@ import ( "github.com/stretchr/testify/require" ) -func (s *DockerClientTestSuite) TestDestroyWorkspace() { - workspaceDir := s.T().TempDir() +func (s *DockerClientTestSuite) TestDestroyTarget() { + targetDir := s.T().TempDir() - err := s.dockerClient.DestroyWorkspace(workspace1, workspaceDir, nil) + err := s.dockerClient.DestroyTarget(target1, targetDir, nil) require.Nil(s.T(), err) - _, err = os.Stat(workspaceDir) + _, err = os.Stat(targetDir) require.True(s.T(), os.IsNotExist(err)) } -func (s *DockerClientTestSuite) TestDestroyProject() { +func (s *DockerClientTestSuite) TestDestroyWorkspace() { s.mockClient.On("ContainerList", mock.Anything, mock.Anything).Return([]types.Container{}, nil) - containerName := s.dockerClient.GetProjectContainerName(project1) + containerName := s.dockerClient.GetWorkspaceContainerName(workspace1) s.mockClient.On("ContainerInspect", mock.Anything, containerName).Return(types.ContainerJSON{ Config: &container.Config{}, @@ -38,13 +38,13 @@ func (s *DockerClientTestSuite) TestDestroyProject() { }, ).Return(nil) - s.mockClient.On("VolumeRemove", mock.Anything, s.dockerClient.GetProjectVolumeName(project1), true).Return(nil) + s.mockClient.On("VolumeRemove", mock.Anything, s.dockerClient.GetWorkspaceVolumeName(workspace1), true).Return(nil) - projectDir := s.T().TempDir() + workspaceDir := s.T().TempDir() - err := s.dockerClient.DestroyProject(project1, projectDir, nil) + err := s.dockerClient.DestroyWorkspace(workspace1, workspaceDir, nil) require.Nil(s.T(), err) - _, err = os.Stat(projectDir) + _, err = os.Stat(workspaceDir) require.True(s.T(), os.IsNotExist(err)) } diff --git a/pkg/docker/exec_test.go b/pkg/docker/exec_test.go index f64e1af70f..b3577da712 100644 --- a/pkg/docker/exec_test.go +++ b/pkg/docker/exec_test.go @@ -18,13 +18,13 @@ import ( func (s *DockerClientTestSuite) TestExecSync() { s.mockClient.On("ContainerList", mock.Anything, mock.Anything).Return([]types.Container{}, nil) - containerName := s.dockerClient.GetProjectContainerName(project1) + containerName := s.dockerClient.GetWorkspaceContainerName(workspace1) - s.setupExecTest([]string{"test-cmd"}, containerName, project1.User, []string{}, "") + s.setupExecTest([]string{"test-cmd"}, containerName, workspace1.User, []string{}, "") result, err := s.dockerClient.ExecSync(containerName, container.ExecOptions{ Cmd: []string{"test-cmd"}, - User: project1.User, + User: workspace1.User, }, io.Discard) require.Nil(s.T(), err) require.Equal(s.T(), 0, result.ExitCode) diff --git a/pkg/docker/info.go b/pkg/docker/info.go deleted file mode 100644 index f6355bbb29..0000000000 --- a/pkg/docker/info.go +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package docker - -import ( - "context" - "encoding/json" - "fmt" - - "github.com/daytonaio/daytona/pkg/workspace" - "github.com/daytonaio/daytona/pkg/workspace/project" - "github.com/docker/docker/api/types" - "github.com/docker/docker/client" -) - -const ContainerNotFoundMetadata = "{\"state\": \"container not found\"}" -const WorkspaceMetadataFormat = "{\"networkId\": \"%s\"}" - -func (d *DockerClient) GetWorkspaceInfo(ws *workspace.Workspace) (*workspace.WorkspaceInfo, error) { - workspaceInfo := &workspace.WorkspaceInfo{ - Name: ws.Name, - ProviderMetadata: fmt.Sprintf(WorkspaceMetadataFormat, ws.Id), - } - - projectInfos := []*project.ProjectInfo{} - for _, project := range ws.Projects { - projectInfo, err := d.GetProjectInfo(project) - if err != nil { - return nil, err - } - projectInfos = append(projectInfos, projectInfo) - } - workspaceInfo.Projects = projectInfos - - return workspaceInfo, nil -} - -func (d *DockerClient) GetProjectInfo(p *project.Project) (*project.ProjectInfo, error) { - isRunning := true - info, err := d.getContainerInfo(p) - if err != nil { - if client.IsErrNotFound(err) { - isRunning = false - } else { - return nil, err - } - } - - if info == nil || info.State == nil { - return &project.ProjectInfo{ - Name: p.Name, - IsRunning: isRunning, - Created: "", - ProviderMetadata: ContainerNotFoundMetadata, - }, nil - } - - projectInfo := &project.ProjectInfo{ - Name: p.Name, - IsRunning: isRunning, - Created: info.Created, - } - - if info.Config != nil && info.Config.Labels != nil { - metadata, err := json.Marshal(info.Config.Labels) - if err != nil { - return nil, err - } - projectInfo.ProviderMetadata = string(metadata) - } - - return projectInfo, nil -} - -func (d *DockerClient) getContainerInfo(p *project.Project) (*types.ContainerJSON, error) { - ctx := context.Background() - - info, err := d.apiClient.ContainerInspect(ctx, d.GetProjectContainerName(p)) - if err != nil { - return nil, err - } - - return &info, nil -} diff --git a/pkg/docker/info_test.go b/pkg/docker/info_test.go deleted file mode 100644 index c016b24a1e..0000000000 --- a/pkg/docker/info_test.go +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package docker_test - -import ( - "fmt" - - "github.com/daytonaio/daytona/pkg/docker" - "github.com/daytonaio/daytona/pkg/workspace" - "github.com/docker/docker/api/types" - "github.com/docker/docker/api/types/container" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" -) - -func (s *DockerClientTestSuite) TestGetProjectInfo() { - s.mockClient.On("ContainerList", mock.Anything, mock.Anything).Return([]types.Container{}, nil) - - containerName := s.dockerClient.GetProjectContainerName(project1) - - inspectResult := types.ContainerJSON{ - ContainerJSONBase: &types.ContainerJSONBase{ - State: &types.ContainerState{ - Running: true, - }, - Created: "test-created", - }, - Config: &container.Config{ - Labels: map[string]string{ - "test": "label", - }, - }, - } - metadata := `{"test":"label"}` - - s.mockClient.On("ContainerInspect", mock.Anything, containerName).Return(inspectResult, nil) - - projectInfo, err := s.dockerClient.GetProjectInfo(project1) - require.Nil(s.T(), err) - require.Equal(s.T(), project1.Name, projectInfo.Name) - require.Equal(s.T(), projectInfo.IsRunning, inspectResult.State.Running) - require.Equal(s.T(), projectInfo.Created, inspectResult.Created) - require.Equal(s.T(), projectInfo.ProviderMetadata, metadata) -} - -func (s *DockerClientTestSuite) TestGetWorkspaceInfo() { - workspaceWithoutProjects := &workspace.Workspace{ - Id: "123", - Name: "test", - Target: "local", - } - - wsInfo, err := s.dockerClient.GetWorkspaceInfo(workspaceWithoutProjects) - require.Nil(s.T(), err) - require.Equal(s.T(), wsInfo.Name, workspaceWithoutProjects.Name) - require.Equal(s.T(), wsInfo.ProviderMetadata, fmt.Sprintf(docker.WorkspaceMetadataFormat, workspaceWithoutProjects.Id)) -} diff --git a/pkg/docker/metadata.go b/pkg/docker/metadata.go new file mode 100644 index 0000000000..a7a81113ba --- /dev/null +++ b/pkg/docker/metadata.go @@ -0,0 +1,45 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package docker + +import ( + "context" + "encoding/json" + "errors" + + "github.com/daytonaio/daytona/pkg/models" + "github.com/docker/docker/api/types" +) + +func (d *DockerClient) GetTargetProviderMetadata(t *models.Target) (string, error) { + return "", nil +} + +func (d *DockerClient) GetWorkspaceProviderMetadata(w *models.Workspace) (string, error) { + info, err := d.getContainerInfo(w) + if err != nil { + return "", err + } + + if info.Config == nil || info.Config.Labels == nil { + return "", errors.New("container labels not found") + } + + metadata, err := json.Marshal(info.Config.Labels) + if err != nil { + return "", err + } + return string(metadata), nil +} + +func (d *DockerClient) getContainerInfo(w *models.Workspace) (*types.ContainerJSON, error) { + ctx := context.Background() + + info, err := d.apiClient.ContainerInspect(ctx, d.GetWorkspaceContainerName(w)) + if err != nil { + return nil, err + } + + return &info, nil +} diff --git a/pkg/docker/metadata_test.go b/pkg/docker/metadata_test.go new file mode 100644 index 0000000000..30c570cce1 --- /dev/null +++ b/pkg/docker/metadata_test.go @@ -0,0 +1,38 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package docker_test + +import ( + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/container" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" +) + +func (s *DockerClientTestSuite) TestGetWorkspaceProviderMetadata() { + s.mockClient.On("ContainerList", mock.Anything, mock.Anything).Return([]types.Container{}, nil) + + containerName := s.dockerClient.GetWorkspaceContainerName(workspace1) + + inspectResult := types.ContainerJSON{ + ContainerJSONBase: &types.ContainerJSONBase{ + State: &types.ContainerState{ + Running: true, + }, + Created: "test-created", + }, + Config: &container.Config{ + Labels: map[string]string{ + "test": "label", + }, + }, + } + metadata := `{"test":"label"}` + + s.mockClient.On("ContainerInspect", mock.Anything, containerName).Return(inspectResult, nil) + + workspaceMetadata, err := s.dockerClient.GetWorkspaceProviderMetadata(workspace1) + require.Nil(s.T(), err) + require.Equal(s.T(), workspaceMetadata, metadata) +} diff --git a/pkg/docker/pull_image.go b/pkg/docker/pull_image.go index 95aa8d5984..d5298b61b7 100644 --- a/pkg/docker/pull_image.go +++ b/pkg/docker/pull_image.go @@ -10,14 +10,15 @@ import ( "io" "strings" - "github.com/daytonaio/daytona/pkg/containerregistry" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/views" "github.com/docker/docker/api/types/filters" "github.com/docker/docker/api/types/image" "github.com/docker/docker/api/types/registry" "github.com/docker/docker/pkg/jsonmessage" ) -func (d *DockerClient) PullImage(imageName string, cr *containerregistry.ContainerRegistry, logWriter io.Writer) error { +func (d *DockerClient) PullImage(imageName string, cr *models.ContainerRegistry, logWriter io.Writer) error { ctx := context.Background() tag := "latest" @@ -68,13 +69,13 @@ func (d *DockerClient) PullImage(imageName string, cr *containerregistry.Contain return err } if logWriter != nil { - logWriter.Write([]byte("Image pulled successfully\n")) + logWriter.Write([]byte(views.GetPrettyLogLine("Image pulled successfully"))) } return nil } -func getRegistryAuth(cr *containerregistry.ContainerRegistry) string { +func getRegistryAuth(cr *models.ContainerRegistry) string { if cr == nil { // Sometimes registry auth fails if "" is sent, so sending "empty" instead return "empty" diff --git a/pkg/docker/push_image.go b/pkg/docker/push_image.go index 6151d25d5e..ca325e8e1a 100644 --- a/pkg/docker/push_image.go +++ b/pkg/docker/push_image.go @@ -7,12 +7,12 @@ import ( "context" "io" - "github.com/daytonaio/daytona/pkg/containerregistry" + "github.com/daytonaio/daytona/pkg/models" "github.com/docker/docker/api/types/image" "github.com/docker/docker/pkg/jsonmessage" ) -func (d *DockerClient) PushImage(imageName string, cr *containerregistry.ContainerRegistry, logWriter io.Writer) error { +func (d *DockerClient) PushImage(imageName string, cr *models.ContainerRegistry, logWriter io.Writer) error { ctx := context.Background() if logWriter != nil { diff --git a/pkg/docker/start.go b/pkg/docker/start.go index d10d993ab5..26c23a465a 100644 --- a/pkg/docker/start.go +++ b/pkg/docker/start.go @@ -11,16 +11,16 @@ import ( "strings" "github.com/daytonaio/daytona/pkg/build/detect" + "github.com/daytonaio/daytona/pkg/models" "github.com/daytonaio/daytona/pkg/provider/util" - "github.com/daytonaio/daytona/pkg/workspace/project" "github.com/docker/docker/api/types/container" ) -func (d *DockerClient) StartProject(opts *CreateProjectOptions, daytonaDownloadUrl string) error { +func (d *DockerClient) StartWorkspace(opts *CreateWorkspaceOptions, daytonaDownloadUrl string) error { var err error - containerUser := opts.Project.User + containerUser := opts.Workspace.User - builderType, err := detect.DetectProjectBuilderType(opts.Project.BuildConfig, opts.ProjectDir, opts.SshClient) + builderType, err := detect.DetectWorkspaceBuilderType(opts.Workspace.BuildConfig, opts.WorkspaceDir, opts.SshClient) if err != nil { return err } @@ -28,10 +28,10 @@ func (d *DockerClient) StartProject(opts *CreateProjectOptions, daytonaDownloadU switch builderType { case detect.BuilderTypeDevcontainer: var remoteUser RemoteUser - remoteUser, err = d.startDevcontainerProject(opts) + remoteUser, err = d.startDevcontainerWorkspace(opts) containerUser = string(remoteUser) case detect.BuilderTypeImage: - err = d.startImageProject(opts) + err = d.startImageWorkspace(opts) default: return fmt.Errorf("unknown builder type: %s", builderType) } @@ -40,18 +40,18 @@ func (d *DockerClient) StartProject(opts *CreateProjectOptions, daytonaDownloadU return err } - return d.startDaytonaAgent(opts.Project, containerUser, daytonaDownloadUrl, opts.LogWriter) + return d.startDaytonaAgent(opts.Workspace, containerUser, daytonaDownloadUrl, opts.LogWriter) } -func (d *DockerClient) startDaytonaAgent(p *project.Project, containerUser, daytonaDownloadUrl string, logWriter io.Writer) error { +func (d *DockerClient) startDaytonaAgent(w *models.Workspace, containerUser, daytonaDownloadUrl string, logWriter io.Writer) error { errChan := make(chan error) - r, w := io.Pipe() - writer := io.MultiWriter(w, logWriter) + r, pipeW := io.Pipe() + writer := io.MultiWriter(pipeW, logWriter) go func() { - result, err := d.ExecSync(d.GetProjectContainerName(p), container.ExecOptions{ - Cmd: []string{"sh", "-c", util.GetProjectStartScript(daytonaDownloadUrl, p.ApiKey)}, + result, err := d.ExecSync(d.GetWorkspaceContainerName(w), container.ExecOptions{ + Cmd: []string{"sh", "-c", util.GetWorkspaceStartScript(daytonaDownloadUrl, w.ApiKey)}, AttachStdout: true, AttachStderr: true, User: containerUser, diff --git a/pkg/docker/start_devcontainer.go b/pkg/docker/start_devcontainer.go index b1ae1a2e39..92aa47cad2 100644 --- a/pkg/docker/start_devcontainer.go +++ b/pkg/docker/start_devcontainer.go @@ -11,7 +11,7 @@ import ( "github.com/docker/docker/api/types/mount" ) -func (d *DockerClient) startDevcontainerProject(opts *CreateProjectOptions) (RemoteUser, error) { +func (d *DockerClient) startDevcontainerWorkspace(opts *CreateWorkspaceOptions) (RemoteUser, error) { go func() { err := d.runDevcontainerUserCommands(opts) if err != nil { @@ -23,31 +23,32 @@ func (d *DockerClient) startDevcontainerProject(opts *CreateProjectOptions) (Rem return remoteUser, err } -func (d *DockerClient) runDevcontainerUserCommands(opts *CreateProjectOptions) error { - socketForwardId, err := d.ensureDockerSockForward(opts.BuilderImage, opts.BuilderContainerRegistry, opts.LogWriter) +func (d *DockerClient) runDevcontainerUserCommands(opts *CreateWorkspaceOptions) error { + cr := opts.ContainerRegistries.FindContainerRegistryByImageName(opts.BuilderImage) + socketForwardId, err := d.ensureDockerSockForward(opts.BuilderImage, cr, opts.LogWriter) if err != nil { return err } opts.LogWriter.Write([]byte("Running devcontainer user commands...\n")) - paths := d.getDevcontainerPaths(opts.ProjectDir, opts.Project.BuildConfig.Devcontainer.FilePath) + paths := d.getDevcontainerPaths(opts.WorkspaceDir, opts.Workspace.BuildConfig.Devcontainer.FilePath) devcontainerCmd := []string{ "devcontainer", "run-user-commands", - "--workspace-folder=" + paths.ProjectTarget, + "--workspace-folder=" + paths.WorkspaceDirTarget, "--config=" + paths.TargetConfigFilePath, "--override-config=" + path.Join(paths.OverridesTarget, "devcontainer.json"), - "--id-label=daytona.workspace.id=" + opts.Project.WorkspaceId, - "--id-label=daytona.project.name=" + opts.Project.Name, + "--id-label=daytona.target.id=" + opts.Workspace.TargetId, + "--id-label=daytona.workspace.id=" + opts.Workspace.Id, } cmd := strings.Join(devcontainerCmd, " ") createDevcontainerOptions := d.toCreateDevcontainerOptions(opts, true) - _, err = d.execDevcontainerCommand(cmd, &createDevcontainerOptions, paths, paths.ProjectTarget, socketForwardId, true, []mount.Mount{ + _, err = d.execDevcontainerCommand(cmd, &createDevcontainerOptions, paths, paths.WorkspaceDirTarget, socketForwardId, true, []mount.Mount{ { Type: mount.TypeBind, Source: paths.OverridesDir, diff --git a/pkg/docker/start_image.go b/pkg/docker/start_image.go index 1ed95a784e..238707bd54 100644 --- a/pkg/docker/start_image.go +++ b/pkg/docker/start_image.go @@ -20,8 +20,8 @@ type FeatureItem struct { // Add other fields as needed } -func (d *DockerClient) startImageProject(opts *CreateProjectOptions) error { - containerName := d.GetProjectContainerName(opts.Project) +func (d *DockerClient) startImageWorkspace(opts *CreateWorkspaceOptions) error { + containerName := d.GetWorkspaceContainerName(opts.Workspace) ctx := context.Background() c, err := d.apiClient.ContainerInspect(ctx, containerName) @@ -109,7 +109,7 @@ func (d *DockerClient) startImageProject(opts *CreateProjectOptions) error { return nil } -func executeEntrypoints(ctx context.Context, cli client.APIClient, containerID string, features []FeatureItem, opts *CreateProjectOptions) error { +func executeEntrypoints(ctx context.Context, cli client.APIClient, containerID string, features []FeatureItem, opts *CreateWorkspaceOptions) error { for _, feature := range features { if feature.Entrypoint != "" { execConfig := container.ExecOptions{ diff --git a/pkg/docker/start_test.go b/pkg/docker/start_test.go index 72a4574155..93f6847879 100644 --- a/pkg/docker/start_test.go +++ b/pkg/docker/start_test.go @@ -12,12 +12,12 @@ import ( "github.com/stretchr/testify/require" ) -func (s *DockerClientTestSuite) TestStartProject() { +func (s *DockerClientTestSuite) TestStartWorkspace() { s.T().Skip("TODO: figure out how to properly test the output of exec") s.mockClient.On("ContainerList", mock.Anything, mock.Anything).Return([]types.Container{}, nil) - containerName := s.dockerClient.GetProjectContainerName(project1) + containerName := s.dockerClient.GetWorkspaceContainerName(workspace1) s.mockClient.On("ContainerStart", mock.Anything, containerName, container.StartOptions{}).Return(nil) s.mockClient.On("ContainerInspect", mock.Anything, containerName).Return(types.ContainerJSON{ @@ -41,10 +41,10 @@ func (s *DockerClientTestSuite) TestStartProject() { }, }, nil) - s.setupExecTest([]string{"sh", "-c", util.GetProjectStartScript("", project1.ApiKey)}, containerName, project1.User, []string{}, "Daytona Agent started") + s.setupExecTest([]string{"sh", "-c", util.GetWorkspaceStartScript("", workspace1.ApiKey)}, containerName, workspace1.User, []string{}, "Daytona Agent started") - err := s.dockerClient.StartProject(&docker.CreateProjectOptions{ - Project: project1, + err := s.dockerClient.StartWorkspace(&docker.CreateWorkspaceOptions{ + Workspace: workspace1, }, "") require.Nil(s.T(), err) } diff --git a/pkg/docker/stop.go b/pkg/docker/stop.go index 631f44f278..a372faacab 100644 --- a/pkg/docker/stop.go +++ b/pkg/docker/stop.go @@ -10,20 +10,22 @@ import ( "strings" "time" - "github.com/daytonaio/daytona/pkg/workspace/project" + "github.com/daytonaio/daytona/pkg/models" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/container" ) -func (d *DockerClient) StopProject(p *project.Project, logWriter io.Writer) error { - return d.stopProjectContainer(p, logWriter) +func (d *DockerClient) StopWorkspace(w *models.Workspace, logWriter io.Writer) error { + return d.stopWorkspaceContainer(w, logWriter) } -func (d *DockerClient) stopProjectContainer(p *project.Project, logWriter io.Writer) error { - containerName := d.GetProjectContainerName(p) +func (d *DockerClient) stopWorkspaceContainer(w *models.Workspace, logWriter io.Writer) error { + containerName := d.GetWorkspaceContainerName(w) ctx := context.Background() - err := d.apiClient.ContainerStop(ctx, containerName, container.StopOptions{}) + err := d.apiClient.ContainerStop(ctx, containerName, container.StopOptions{ + Signal: "SIGKILL", + }) if err != nil { return err } @@ -59,7 +61,9 @@ func (d *DockerClient) stopProjectContainer(p *project.Project, logWriter io.Wri } for _, c := range composeContainers { - err = d.apiClient.ContainerStop(ctx, c.ID, container.StopOptions{}) + err = d.apiClient.ContainerStop(ctx, c.ID, container.StopOptions{ + Signal: "SIGKILL", + }) if err != nil { return err } diff --git a/pkg/docker/stop_test.go b/pkg/docker/stop_test.go index 6188f2e43c..2848c436fe 100644 --- a/pkg/docker/stop_test.go +++ b/pkg/docker/stop_test.go @@ -10,12 +10,14 @@ import ( "github.com/stretchr/testify/require" ) -func (s *DockerClientTestSuite) TestStopProject() { +func (s *DockerClientTestSuite) TestStopWorkspace() { s.mockClient.On("ContainerList", mock.Anything, mock.Anything).Return([]types.Container{}, nil) - containerName := s.dockerClient.GetProjectContainerName(project1) + containerName := s.dockerClient.GetWorkspaceContainerName(workspace1) - s.mockClient.On("ContainerStop", mock.Anything, containerName, container.StopOptions{}).Return(nil) + s.mockClient.On("ContainerStop", mock.Anything, containerName, container.StopOptions{ + Signal: "SIGKILL", + }).Return(nil) s.mockClient.On("ContainerInspect", mock.Anything, containerName).Return(types.ContainerJSON{ ContainerJSONBase: &types.ContainerJSONBase{ State: &types.ContainerState{ @@ -27,6 +29,6 @@ func (s *DockerClientTestSuite) TestStopProject() { }, }, nil) - err := s.dockerClient.StopProject(project1, nil) + err := s.dockerClient.StopWorkspace(workspace1, nil) require.Nil(s.T(), err) } diff --git a/pkg/git/add.go b/pkg/git/add.go index b78aae41d3..5ea0d7c00a 100644 --- a/pkg/git/add.go +++ b/pkg/git/add.go @@ -6,7 +6,7 @@ package git import "github.com/go-git/go-git/v5" func (s *Service) Add(files []string) error { - repo, err := git.PlainOpen(s.ProjectDir) + repo, err := git.PlainOpen(s.WorkspaceDir) if err != nil { return err } diff --git a/pkg/git/branch.go b/pkg/git/branch.go index f97c799bb2..d605892fd6 100644 --- a/pkg/git/branch.go +++ b/pkg/git/branch.go @@ -9,7 +9,7 @@ import ( ) func (s *Service) CreateBranch(name string) error { - repo, err := git.PlainOpen(s.ProjectDir) + repo, err := git.PlainOpen(s.WorkspaceDir) if err != nil { return err } @@ -26,7 +26,7 @@ func (s *Service) CreateBranch(name string) error { } func (s *Service) ListBranches() ([]string, error) { - repo, err := git.PlainOpen(s.ProjectDir) + repo, err := git.PlainOpen(s.WorkspaceDir) if err != nil { return []string{}, err } diff --git a/pkg/git/clone.go b/pkg/git/clone.go index 6e5fae4f6d..0f05c827f2 100644 --- a/pkg/git/clone.go +++ b/pkg/git/clone.go @@ -38,13 +38,13 @@ func (s *Service) CloneRepository(repo *gitprovider.GitRepository, auth *http.Ba cloneOptions.ReferenceName = plumbing.ReferenceName("refs/heads/" + repo.Branch) - _, err := git.PlainClone(s.ProjectDir, false, cloneOptions) + _, err := git.PlainClone(s.WorkspaceDir, false, cloneOptions) if err != nil { return err } if repo.Target == gitprovider.CloneTargetCommit { - r, err := git.PlainOpen(s.ProjectDir) + r, err := git.PlainOpen(s.WorkspaceDir) if err != nil { return err } @@ -78,10 +78,10 @@ func (s *Service) CloneRepositoryCmd(repo *gitprovider.GitRepository, auth *http cloneUrl = fmt.Sprintf("%s://%s:%s@%s", strings.Split(cloneUrl, "://")[0], auth.Username, auth.Password, strings.SplitN(cloneUrl, "://", 2)[1]) } - cloneCmd = append(cloneCmd, cloneUrl, s.ProjectDir) + cloneCmd = append(cloneCmd, cloneUrl, s.WorkspaceDir) if repo.Target == gitprovider.CloneTargetCommit { - cloneCmd = append(cloneCmd, "&&", "cd", s.ProjectDir) + cloneCmd = append(cloneCmd, "&&", "cd", s.WorkspaceDir) cloneCmd = append(cloneCmd, "&&", "git", "checkout", repo.Sha) } diff --git a/pkg/git/commit.go b/pkg/git/commit.go index 6acd3583dd..b515207413 100644 --- a/pkg/git/commit.go +++ b/pkg/git/commit.go @@ -6,7 +6,7 @@ package git import "github.com/go-git/go-git/v5" func (s *Service) Commit(message string, options *git.CommitOptions) (string, error) { - repo, err := git.PlainOpen(s.ProjectDir) + repo, err := git.PlainOpen(s.WorkspaceDir) if err != nil { return "", err } diff --git a/pkg/git/config.go b/pkg/git/config.go index b1a6638e02..1ba90a4011 100644 --- a/pkg/git/config.go +++ b/pkg/git/config.go @@ -10,10 +10,11 @@ import ( "path/filepath" "github.com/daytonaio/daytona/pkg/gitprovider" + "github.com/daytonaio/daytona/pkg/models" "gopkg.in/ini.v1" ) -func (s *Service) SetGitConfig(userData *gitprovider.GitUser, providerConfig *gitprovider.GitProviderConfig) error { +func (s *Service) SetGitConfig(userData *gitprovider.GitUser, providerConfig *models.GitProviderConfig) error { gitConfigFileName := s.GitConfigFileName var gitConfigContent []byte @@ -45,7 +46,7 @@ func (s *Service) SetGitConfig(userData *gitprovider.GitUser, providerConfig *gi return err } } - _, err = cfg.Section("safe").NewKey("directory", s.ProjectDir) + _, err = cfg.Section("safe").NewKey("directory", s.WorkspaceDir) if err != nil { return err } @@ -82,7 +83,7 @@ func (s *Service) SetGitConfig(userData *gitprovider.GitUser, providerConfig *gi return os.WriteFile(gitConfigFileName, buf.Bytes(), 0644) } -func (s *Service) setSigningConfig(cfg *ini.File, providerConfig *gitprovider.GitProviderConfig, userData *gitprovider.GitUser) error { +func (s *Service) setSigningConfig(cfg *ini.File, providerConfig *models.GitProviderConfig, userData *gitprovider.GitUser) error { if providerConfig == nil || providerConfig.SigningMethod == nil || providerConfig.SigningKey == nil { return nil } @@ -107,12 +108,12 @@ func (s *Service) setSigningConfig(cfg *ini.File, providerConfig *gitprovider.Gi } switch *providerConfig.SigningMethod { - case gitprovider.SigningMethodGPG: + case models.SigningMethodGPG: _, err := cfg.Section("commit").NewKey("gpgSign", "true") if err != nil { return err } - case gitprovider.SigningMethodSSH: + case models.SigningMethodSSH: err := s.configureAllowedSigners(userData.Email, *providerConfig.SigningKey) if err != nil { return err diff --git a/pkg/git/log.go b/pkg/git/log.go index dca50c0b59..79d92f2c36 100644 --- a/pkg/git/log.go +++ b/pkg/git/log.go @@ -10,7 +10,7 @@ import ( ) func (s *Service) Log() ([]GitCommitInfo, error) { - repo, err := git.PlainOpen(s.ProjectDir) + repo, err := git.PlainOpen(s.WorkspaceDir) if err != nil { return []GitCommitInfo{}, err } diff --git a/pkg/git/pull.go b/pkg/git/pull.go index bd86ccd188..5ae24ba201 100644 --- a/pkg/git/pull.go +++ b/pkg/git/pull.go @@ -10,7 +10,7 @@ import ( ) func (s *Service) Pull(auth *http.BasicAuth) error { - repo, err := git.PlainOpen(s.ProjectDir) + repo, err := git.PlainOpen(s.WorkspaceDir) if err != nil { return err } diff --git a/pkg/git/push.go b/pkg/git/push.go index abbd23d89f..6d98822754 100644 --- a/pkg/git/push.go +++ b/pkg/git/push.go @@ -10,7 +10,7 @@ import ( ) func (s *Service) Push(auth *http.BasicAuth) error { - repo, err := git.PlainOpen(s.ProjectDir) + repo, err := git.PlainOpen(s.WorkspaceDir) if err != nil { return err } diff --git a/pkg/git/service.go b/pkg/git/service.go index 38fb5bf4e5..09c8a52e69 100644 --- a/pkg/git/service.go +++ b/pkg/git/service.go @@ -9,39 +9,39 @@ import ( "path/filepath" "github.com/daytonaio/daytona/pkg/gitprovider" - "github.com/daytonaio/daytona/pkg/workspace/project" + "github.com/daytonaio/daytona/pkg/models" "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/plumbing/transport/http" ) -var MapStatus map[git.StatusCode]project.Status = map[git.StatusCode]project.Status{ - git.Unmodified: project.Unmodified, - git.Untracked: project.Untracked, - git.Modified: project.Modified, - git.Added: project.Added, - git.Deleted: project.Deleted, - git.Renamed: project.Renamed, - git.Copied: project.Copied, - git.UpdatedButUnmerged: project.UpdatedButUnmerged, +var MapStatus map[git.StatusCode]models.Status = map[git.StatusCode]models.Status{ + git.Unmodified: models.Unmodified, + git.Untracked: models.Untracked, + git.Modified: models.Modified, + git.Added: models.Added, + git.Deleted: models.Deleted, + git.Renamed: models.Renamed, + git.Copied: models.Copied, + git.UpdatedButUnmerged: models.UpdatedButUnmerged, } type IGitService interface { CloneRepository(repo *gitprovider.GitRepository, auth *http.BasicAuth) error CloneRepositoryCmd(repo *gitprovider.GitRepository, auth *http.BasicAuth) []string RepositoryExists() (bool, error) - SetGitConfig(userData *gitprovider.GitUser, providerConfig *gitprovider.GitProviderConfig) error - GetGitStatus() (*project.GitStatus, error) + SetGitConfig(userData *gitprovider.GitUser, providerConfig *models.GitProviderConfig) error + GetGitStatus() (*models.GitStatus, error) } type Service struct { - ProjectDir string + WorkspaceDir string GitConfigFileName string LogWriter io.Writer OpenRepository *git.Repository } func (s *Service) RepositoryExists() (bool, error) { - _, err := os.Stat(filepath.Join(s.ProjectDir, ".git")) + _, err := os.Stat(filepath.Join(s.WorkspaceDir, ".git")) if os.IsNotExist(err) { return false, nil } diff --git a/pkg/git/service_test.go b/pkg/git/service_test.go index f1d7ad4b26..32ba546ed1 100644 --- a/pkg/git/service_test.go +++ b/pkg/git/service_test.go @@ -61,7 +61,7 @@ func NewGitServiceTestSuite() *GitServiceTestSuite { func (s *GitServiceTestSuite) SetupTest() { s.gitService = &git.Service{ - ProjectDir: "/workdir", + WorkspaceDir: "/workdir", } } diff --git a/pkg/git/status.go b/pkg/git/status.go index f8f202a080..c6fe7325ff 100644 --- a/pkg/git/status.go +++ b/pkg/git/status.go @@ -9,12 +9,12 @@ import ( "strconv" "strings" - "github.com/daytonaio/daytona/pkg/workspace/project" + "github.com/daytonaio/daytona/pkg/models" "github.com/go-git/go-git/v5" ) -func (s *Service) GetGitStatus() (*project.GitStatus, error) { - repo, err := git.PlainOpen(s.ProjectDir) +func (s *Service) GetGitStatus() (*models.GitStatus, error) { + repo, err := git.PlainOpen(s.WorkspaceDir) if err != nil { return nil, err } @@ -34,9 +34,9 @@ func (s *Service) GetGitStatus() (*project.GitStatus, error) { return nil, err } - files := []*project.FileStatus{} + files := []*models.FileStatus{} for path, file := range status { - files = append(files, &project.FileStatus{ + files = append(files, &models.FileStatus{ Name: path, Extra: file.Extra, Staging: MapStatus[file.Staging], @@ -54,7 +54,7 @@ func (s *Service) GetGitStatus() (*project.GitStatus, error) { return nil, err } - return &project.GitStatus{ + return &models.GitStatus{ CurrentBranch: ref.Name().Short(), Files: files, BranchPublished: branchPublished, @@ -72,7 +72,7 @@ func (s *Service) isBranchPublished() (bool, error) { } func (s *Service) getUpstreamBranch() (string, error) { - cmd := exec.Command("git", "-C", s.ProjectDir, "rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{upstream}") + cmd := exec.Command("git", "-C", s.WorkspaceDir, "rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{upstream}") out, err := cmd.CombinedOutput() if err != nil { return "", nil @@ -90,7 +90,7 @@ func (s *Service) getAheadBehindInfo() (int, int, error) { return 0, 0, nil } - cmd := exec.Command("git", "-C", s.ProjectDir, "rev-list", "--left-right", "--count", fmt.Sprintf("%s...HEAD", upstream)) + cmd := exec.Command("git", "-C", s.WorkspaceDir, "rev-list", "--left-right", "--count", fmt.Sprintf("%s...HEAD", upstream)) out, err := cmd.CombinedOutput() if err != nil { return 0, 0, nil diff --git a/pkg/gitprovider/store.go b/pkg/gitprovider/store.go deleted file mode 100644 index b60b56f911..0000000000 --- a/pkg/gitprovider/store.go +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package gitprovider - -import "errors" - -type ConfigStore interface { - List() ([]*GitProviderConfig, error) - Find(id string) (*GitProviderConfig, error) - Save(*GitProviderConfig) error - Delete(*GitProviderConfig) error -} - -var ( - ErrGitProviderConfigNotFound = errors.New("git provider config not found") -) - -func IsGitProviderNotFound(err error) bool { - return err.Error() == ErrGitProviderConfigNotFound.Error() -} diff --git a/pkg/gitprovider/types.go b/pkg/gitprovider/types.go index 5b38d2e310..71f2daab15 100644 --- a/pkg/gitprovider/types.go +++ b/pkg/gitprovider/types.go @@ -3,24 +3,6 @@ package gitprovider -type SigningMethod string // @name SigningMethod - -const ( - SigningMethodSSH SigningMethod = "ssh" - SigningMethodGPG SigningMethod = "gpg" -) - -type GitProviderConfig struct { - Id string `json:"id" validate:"required"` - ProviderId string `json:"providerId" validate:"required"` - Username string `json:"username" validate:"required"` - BaseApiUrl *string `json:"baseApiUrl,omitempty" validate:"optional"` - Token string `json:"token" validate:"required"` - Alias string `json:"alias" validate:"required"` - SigningKey *string `json:"signingKey,omitempty" validate:"optional"` - SigningMethod *SigningMethod `json:"signingMethod,omitempty" validate:"optional"` -} // @name GitProvider - type GitUser struct { Id string `json:"id" validate:"required"` Username string `json:"username" validate:"required"` diff --git a/pkg/ide/browser.go b/pkg/ide/browser.go index 1ad9c99382..89af2fd864 100644 --- a/pkg/ide/browser.go +++ b/pkg/ide/browser.go @@ -23,17 +23,17 @@ import ( const startVSCodeServerCommand = "$HOME/vscode-server/bin/openvscode-server --start-server --port=63000 --host=0.0.0.0 --without-connection-token --disable-workspace-trust --default-folder=" -func OpenBrowserIDE(activeProfile config.Profile, workspaceId string, projectName string, projectProviderMetadata string, gpgKey string) error { +func OpenBrowserIDE(activeProfile config.Profile, workspaceId string, workspaceProviderMetadata string, gpgKey *string) error { // Download and start IDE - err := config.EnsureSshConfigEntryAdded(activeProfile.Id, workspaceId, projectName, gpgKey) + err := config.EnsureSshConfigEntryAdded(activeProfile.Id, workspaceId, gpgKey) if err != nil { return err } views.RenderInfoMessageBold("Downloading OpenVSCode Server...") - projectHostname := config.GetProjectHostname(activeProfile.Id, workspaceId, projectName) + workspaceHostname := config.GetHostname(activeProfile.Id, workspaceId) - installServerCommand := exec.Command("ssh", projectHostname, "curl -fsSL https://download.daytona.io/daytona/get-openvscode-server.sh | sh") + installServerCommand := exec.Command("ssh", workspaceHostname, "curl -fsSL https://download.daytona.io/daytona/get-openvscode-server.sh | sh") installServerCommand.Stdout = io.Writer(&util.DebugLogWriter{}) installServerCommand.Stderr = io.Writer(&util.DebugLogWriter{}) @@ -42,7 +42,7 @@ func OpenBrowserIDE(activeProfile config.Profile, workspaceId string, projectNam return err } - projectDir, err := util.GetProjectDir(activeProfile, workspaceId, projectName, gpgKey) + workspaceDir, err := util.GetWorkspaceDir(activeProfile, workspaceId, gpgKey) if err != nil { return err } @@ -50,7 +50,7 @@ func OpenBrowserIDE(activeProfile config.Profile, workspaceId string, projectNam views.RenderInfoMessageBold("Starting OpenVSCode Server...") go func() { - startServerCommand := exec.CommandContext(context.Background(), "ssh", projectHostname, fmt.Sprintf("%s%s", startVSCodeServerCommand, projectDir)) + startServerCommand := exec.CommandContext(context.Background(), "ssh", workspaceHostname, fmt.Sprintf("%s%s", startVSCodeServerCommand, workspaceDir)) startServerCommand.Stdout = io.Writer(&util.DebugLogWriter{}) startServerCommand.Stderr = io.Writer(&util.DebugLogWriter{}) @@ -61,7 +61,7 @@ func OpenBrowserIDE(activeProfile config.Profile, workspaceId string, projectNam }() // Forward IDE port - browserPort, errChan := tailscale.ForwardPort(workspaceId, projectName, 63000, activeProfile) + browserPort, errChan := tailscale.ForwardPort(workspaceId, 63000, activeProfile) if browserPort == nil { if err := <-errChan; err != nil { return err @@ -77,18 +77,18 @@ func OpenBrowserIDE(activeProfile config.Profile, workspaceId string, projectNam time.Sleep(500 * time.Millisecond) } - views.RenderInfoMessageBold(fmt.Sprintf("Forwarded %s IDE port to %s.\nOpening browser...\n", projectName, ideURL)) + views.RenderInfoMessageBold(fmt.Sprintf("Forwarded %s IDE port to %s.\nOpening browser...\n", workspaceId, ideURL)) err = browser.OpenURL(ideURL) if err != nil { log.Error("Error opening URL: " + err.Error()) } - if projectProviderMetadata == "" { + if workspaceProviderMetadata == "" { return nil } - err = setupVSCodeCustomizations(projectHostname, projectProviderMetadata, devcontainer.Browser, "*/vscode-server/bin/openvscode-server", "$HOME/.openvscode-server/data/Machine/settings.json", ".daytona-customizations-lock-vscode-browser") + err = setupVSCodeCustomizations(workspaceHostname, workspaceProviderMetadata, devcontainer.Browser, "*/vscode-server/bin/openvscode-server", "$HOME/.openvscode-server/data/Machine/settings.json", ".daytona-customizations-lock-vscode-browser") if err != nil { log.Errorf("Error setting up IDE customizations: %s", err) } diff --git a/pkg/ide/cursor.go b/pkg/ide/cursor.go index 00e63fbc58..c1bd38c563 100644 --- a/pkg/ide/cursor.go +++ b/pkg/ide/cursor.go @@ -14,20 +14,20 @@ import ( "github.com/daytonaio/daytona/pkg/build/devcontainer" ) -func OpenCursor(activeProfile config.Profile, workspaceId string, projectName string, projectProviderMetadata string, gpgkey string) error { +func OpenCursor(activeProfile config.Profile, workspaceId string, workspaceProviderMetadata string, gpgKey *string) error { path, err := GetCursorBinaryPath() if err != nil { return err } - projectHostname := config.GetProjectHostname(activeProfile.Id, workspaceId, projectName) + workspaceHostname := config.GetHostname(activeProfile.Id, workspaceId) - projectDir, err := util.GetProjectDir(activeProfile, workspaceId, projectName, gpgkey) + workspaceDir, err := util.GetWorkspaceDir(activeProfile, workspaceId, gpgKey) if err != nil { return err } - commandArgument := fmt.Sprintf("vscode-remote://ssh-remote+%s/%s", projectHostname, projectDir) + commandArgument := fmt.Sprintf("vscode-remote://ssh-remote+%s/%s", workspaceHostname, workspaceDir) cursorCommand := exec.Command(path, "--disable-extension", "ms-vscode-remote.remote-containers", "--folder-uri", commandArgument) @@ -36,11 +36,11 @@ func OpenCursor(activeProfile config.Profile, workspaceId string, projectName st return err } - if projectProviderMetadata == "" { + if workspaceProviderMetadata == "" { return nil } - return setupVSCodeCustomizations(projectHostname, projectProviderMetadata, devcontainer.Vscode, "*/.cursor-server/*/bin/cursor-server", "$HOME/.cursor-server/data/Machine/settings.json", ".daytona-customizations-lock-cursor") + return setupVSCodeCustomizations(workspaceHostname, workspaceProviderMetadata, devcontainer.Vscode, "*/.cursor-server/*/bin/cursor-server", "$HOME/.cursor-server/data/Machine/settings.json", ".daytona-customizations-lock-cursor") } func GetCursorBinaryPath() (string, error) { diff --git a/pkg/ide/fleet.go b/pkg/ide/fleet.go index 4f39157d1f..4f784792b4 100644 --- a/pkg/ide/fleet.go +++ b/pkg/ide/fleet.go @@ -13,18 +13,18 @@ import ( log "github.com/sirupsen/logrus" ) -func OpenFleet(activeProfile config.Profile, workspaceId string, projectName string, gpgKey string) error { +func OpenFleet(activeProfile config.Profile, workspaceId string, gpgKey *string) error { if err := CheckFleetInstallation(); err != nil { return err } - projectHostname := config.GetProjectHostname(activeProfile.Id, workspaceId, projectName) - projectDir, err := util.GetProjectDir(activeProfile, workspaceId, projectName, gpgKey) + workspaceHostname := config.GetHostname(activeProfile.Id, workspaceId) + workspaceDir, err := util.GetWorkspaceDir(activeProfile, workspaceId, gpgKey) if err != nil { return err } - ideURL := fmt.Sprintf("fleet://fleet.ssh/%s?pwd=%s", projectHostname, projectDir) + ideURL := fmt.Sprintf("fleet://fleet.ssh/%s?pwd=%s", workspaceHostname, workspaceDir) err = browser.OpenURL(ideURL) if err != nil { diff --git a/pkg/ide/jetbrains.go b/pkg/ide/jetbrains.go index 4ddc570765..9d8ee26693 100644 --- a/pkg/ide/jetbrains.go +++ b/pkg/ide/jetbrains.go @@ -23,25 +23,25 @@ import ( "github.com/pkg/browser" ) -func OpenJetbrainsIDE(activeProfile config.Profile, ide, workspaceId, projectName string, gpgKey string) error { +func OpenJetbrainsIDE(activeProfile config.Profile, ide, workspaceId string, gpgKey *string) error { err := IsJetBrainsGatewayInstalled() if err != nil { return err } - projectDir, err := util.GetProjectDir(activeProfile, workspaceId, projectName, gpgKey) + workspaceDir, err := util.GetWorkspaceDir(activeProfile, workspaceId, gpgKey) if err != nil { return err } - projectHostname := config.GetProjectHostname(activeProfile.Id, workspaceId, projectName) + workspaceHostname := config.GetHostname(activeProfile.Id, workspaceId) jbIde, ok := jetbrains.GetIdes()[jetbrains.Id(ide)] if !ok { return errors.New("IDE not found") } - home, err := util.GetHomeDir(activeProfile, workspaceId, projectName, gpgKey) + home, err := util.GetHomeDir(activeProfile, workspaceId, gpgKey) if err != nil { return err } @@ -50,7 +50,7 @@ func OpenJetbrainsIDE(activeProfile config.Profile, ide, workspaceId, projectNam downloadUrl := "" - remoteOs, err := util.GetRemoteOS(projectHostname) + remoteOs, err := util.GetRemoteOS(workspaceHostname) if err != nil { return err } @@ -69,25 +69,25 @@ func OpenJetbrainsIDE(activeProfile config.Profile, ide, workspaceId, projectNam return errors.New("JetBrains remote IDEs are only supported on Linux.") } - err = downloadJetbrainsIDE(projectHostname, downloadUrl, downloadPath) + err = downloadJetbrainsIDE(workspaceHostname, downloadUrl, downloadPath) if err != nil { return err } - gatewayUrl := fmt.Sprintf("jetbrains-gateway://connect#host=%s&type=ssh&deploy=false&projectPath=%s&user=daytona&port=%d&idePath=%s", projectHostname, projectDir, ssh_config.SSH_PORT, url.QueryEscape(downloadPath)) + gatewayUrl := fmt.Sprintf("jetbrains-gateway://connect#host=%s&type=ssh&deploy=false&projectPath=%s&user=daytona&port=%d&idePath=%s", workspaceHostname, workspaceDir, ssh_config.SSH_PORT, url.QueryEscape(downloadPath)) return browser.OpenURL(gatewayUrl) } -func downloadJetbrainsIDE(projectHostname, downloadUrl, downloadPath string) error { - if isAlreadyDownloaded(projectHostname, downloadPath) { +func downloadJetbrainsIDE(workspaceHostname, downloadUrl, downloadPath string) error { + if isAlreadyDownloaded(workspaceHostname, downloadPath) { views.RenderInfoMessage("JetBrains IDE already downloaded. Opening...") return nil } - views.RenderInfoMessage(fmt.Sprintf("Downloading the IDE into the project from %s...", downloadUrl)) + views.RenderInfoMessage(fmt.Sprintf("Downloading the IDE into the workspace from %s...", downloadUrl)) - downloadIdeCmd := exec.Command("ssh", projectHostname, fmt.Sprintf("mkdir -p %s && wget -q --show-progress --progress=bar:force -pO- %s | tar -xzC %s --strip-components=1", downloadPath, downloadUrl, downloadPath)) + downloadIdeCmd := exec.Command("ssh", workspaceHostname, fmt.Sprintf("mkdir -p %s && wget -q --show-progress --progress=bar:force -pO- %s | tar -xzC %s --strip-components=1", downloadPath, downloadUrl, downloadPath)) downloadIdeCmd.Stdout = os.Stdout downloadIdeCmd.Stderr = os.Stderr @@ -101,8 +101,8 @@ func downloadJetbrainsIDE(projectHostname, downloadUrl, downloadPath string) err return nil } -func isAlreadyDownloaded(projectHostname, downloadPath string) bool { - statCmd := exec.Command("ssh", projectHostname, fmt.Sprintf("stat %s", downloadPath)) +func isAlreadyDownloaded(workspaceHostname, downloadPath string) bool { + statCmd := exec.Command("ssh", workspaceHostname, fmt.Sprintf("stat %s", downloadPath)) err := statCmd.Run() return err == nil } diff --git a/pkg/ide/jupyter.go b/pkg/ide/jupyter.go index c60ade2f17..34315be676 100644 --- a/pkg/ide/jupyter.go +++ b/pkg/ide/jupyter.go @@ -25,33 +25,33 @@ import ( const startJupyterCommand = "notebook --no-browser --port=8888 --ip=0.0.0.0 --NotebookApp.token='' --NotebookApp.password=''" -// OpenJupyterIDE manages the installation and startup of a Jupyter IDE on a remote workspace. -func OpenJupyterIDE(activeProfile config.Profile, workspaceId, projectName, projectProviderMetadata string, yesFlag bool, gpgKey string) error { +// OpenJupyterIDE manages the installation and startup of a Jupyter IDE on a remote target. +func OpenJupyterIDE(activeProfile config.Profile, workspaceId, workspaceProviderMetadata string, yesFlag bool, gpgKey *string) error { // Ensure SSH config entry is added - err := config.EnsureSshConfigEntryAdded(activeProfile.Id, workspaceId, projectName, gpgKey) + err := config.EnsureSshConfigEntryAdded(activeProfile.Id, workspaceId, gpgKey) if err != nil { return err } - projectHostname := config.GetProjectHostname(activeProfile.Id, workspaceId, projectName) + workspaceHostname := config.GetHostname(activeProfile.Id, workspaceId) // Check and install Python if necessary - if err := ensurePythonInstalled(projectHostname, yesFlag); err != nil { + if err := ensurePythonInstalled(workspaceHostname, yesFlag); err != nil { return err } // Check and install pip if necessary - if err := ensurePipInstalled(projectHostname, yesFlag); err != nil { + if err := ensurePipInstalled(workspaceHostname, yesFlag); err != nil { return err } // Check and install Jupyter Notebook if necessary - if err := ensureJupyterInstalled(projectHostname); err != nil { + if err := ensureJupyterInstalled(workspaceHostname); err != nil { return err } // Start Jupyter Notebook server - if err := startJupyterServer(projectHostname, activeProfile, workspaceId, projectName, gpgKey); err != nil { + if err := startJupyterServer(workspaceHostname, activeProfile, workspaceId, gpgKey); err != nil { return err } @@ -215,9 +215,9 @@ func ensureJupyterInstalled(hostname string) error { return runRemoteCommand(hostname, installCmd) } -// startJupyterServer starts the Jupyter Notebook server on the remote workspace. -func startJupyterServer(hostname string, activeProfile config.Profile, workspaceId, projectName string, gpgKey string) error { - projectDir, err := util.GetProjectDir(activeProfile, workspaceId, projectName, gpgKey) +// startJupyterServer starts the Jupyter Notebook server on the remote target. +func startJupyterServer(hostname string, activeProfile config.Profile, workspaceId string, gpgKey *string) error { + workspaceDir, err := util.GetWorkspaceDir(activeProfile, workspaceId, gpgKey) if err != nil { return err } @@ -226,7 +226,7 @@ func startJupyterServer(hostname string, activeProfile config.Profile, workspace // Start Jupyter Notebook server in the background go func() { - cmd := exec.CommandContext(context.Background(), "ssh", hostname, fmt.Sprintf(". ~/.jupyter_venv/bin/activate && cd %s && jupyter %s", projectDir, startJupyterCommand)) + cmd := exec.CommandContext(context.Background(), "ssh", hostname, fmt.Sprintf(". ~/.jupyter_venv/bin/activate && cd %s && jupyter %s", workspaceDir, startJupyterCommand)) cmd.Stdout = io.Writer(&util.DebugLogWriter{}) cmd.Stderr = io.Writer(&util.DebugLogWriter{}) if err := cmd.Run(); err != nil { @@ -235,7 +235,7 @@ func startJupyterServer(hostname string, activeProfile config.Profile, workspace }() // Forward the IDE port - browserPort, errChan := tailscale.ForwardPort(workspaceId, projectName, 8888, activeProfile) + browserPort, errChan := tailscale.ForwardPort(workspaceId, 8888, activeProfile) if browserPort == nil { if err := <-errChan; err != nil { return err @@ -246,7 +246,7 @@ func startJupyterServer(hostname string, activeProfile config.Profile, workspace ideURL := fmt.Sprintf("http://localhost:%d", *browserPort) waitForPort(*browserPort) - views.RenderInfoMessageBold(fmt.Sprintf("Forwarded %s Jupyter Notebook port to %s.\nOpening browser...\n", projectName, ideURL)) + views.RenderInfoMessageBold(fmt.Sprintf("Forwarded %s Jupyter Notebook port to %s.\nOpening browser...\n", workspaceId, ideURL)) if err := browser.OpenURL(ideURL); err != nil { log.Error("Error opening URL: " + err.Error()) diff --git a/pkg/ide/positron.go b/pkg/ide/positron.go index d26f4c5cfc..7e7538d12c 100644 --- a/pkg/ide/positron.go +++ b/pkg/ide/positron.go @@ -15,20 +15,20 @@ import ( "github.com/daytonaio/daytona/pkg/views" ) -func OpenPositron(activeProfile config.Profile, workspaceId string, projectName string, projectProviderMetadata string, gpgkey string) error { +func OpenPositron(activeProfile config.Profile, workspaceId string, workspaceProviderMetadata string, gpgkey *string) error { path, err := GetPositronBinaryPath() if err != nil { return err } - projectHostname := config.GetProjectHostname(activeProfile.Id, workspaceId, projectName) + workspaceHostname := config.GetHostname(activeProfile.Id, workspaceId) - projectDir, err := util.GetProjectDir(activeProfile, workspaceId, projectName, gpgkey) + workspaceDir, err := util.GetWorkspaceDir(activeProfile, workspaceId, gpgkey) if err != nil { return err } - commandArgument := fmt.Sprintf("vscode-remote://ssh-remote+%s/%s", projectHostname, projectDir) + commandArgument := fmt.Sprintf("vscode-remote://ssh-remote+%s/%s", workspaceHostname, workspaceDir) if runtime.GOARCH == "arm64" { printPositronDisclaimer() } @@ -39,11 +39,11 @@ func OpenPositron(activeProfile config.Profile, workspaceId string, projectName return err } - if projectProviderMetadata == "" { + if workspaceProviderMetadata == "" { return nil } - return setupVSCodeCustomizations(projectHostname, projectProviderMetadata, devcontainer.Vscode, "*/.positron-server/*/bin/positron-server", "$HOME/.positron-server/data/Machine/settings.json", ".daytona-customizations-lock-positron") + return setupVSCodeCustomizations(workspaceHostname, workspaceProviderMetadata, devcontainer.Vscode, "*/.positron-server/*/bin/positron-server", "$HOME/.positron-server/data/Machine/settings.json", ".daytona-customizations-lock-positron") } func GetPositronBinaryPath() (string, error) { diff --git a/pkg/ide/terminal.go b/pkg/ide/terminal.go index 3acbaa19ff..5b61d4c4d4 100644 --- a/pkg/ide/terminal.go +++ b/pkg/ide/terminal.go @@ -12,8 +12,8 @@ import ( "github.com/daytonaio/daytona/cmd/daytona/config" ) -func OpenTerminalSsh(activeProfile config.Profile, workspaceId string, projectName string, gpgKey string, sshOptions []string, args ...string) error { - if err := config.EnsureSshConfigEntryAdded(activeProfile.Id, workspaceId, projectName, gpgKey); err != nil { +func OpenTerminalSsh(activeProfile config.Profile, resourceId string, gpgKey *string, sshOptions []string, args ...string) error { + if err := config.EnsureSshConfigEntryAdded(activeProfile.Id, resourceId, gpgKey); err != nil { return err } @@ -23,8 +23,8 @@ func OpenTerminalSsh(activeProfile config.Profile, workspaceId string, projectNa return err } - projectHostname := config.GetProjectHostname(activeProfile.Id, workspaceId, projectName) - cmdArgs := buildCommandArgs(projectHostname, parsedOptions, args...) + resourceHostname := config.GetHostname(activeProfile.Id, resourceId) + cmdArgs := buildCommandArgs(resourceHostname, parsedOptions, args...) sshCommand := exec.Command("ssh", cmdArgs...) sshCommand.Stdin = os.Stdin @@ -50,8 +50,8 @@ func parseSshOptions(sshOptions []string) (map[string]string, error) { return parsedOptions, nil } -func buildCommandArgs(projectHostname string, parsedOptions map[string]string, args ...string) []string { - cmdArgs := []string{projectHostname} +func buildCommandArgs(resourceHostname string, parsedOptions map[string]string, args ...string) []string { + cmdArgs := []string{resourceHostname} for key, value := range parsedOptions { cmdArgs = append(cmdArgs, "-o", fmt.Sprintf("%s=%s", key, value)) } diff --git a/pkg/ide/vscode-insiders.go b/pkg/ide/vscode-insiders.go index e204f3be1b..019c12aace 100644 --- a/pkg/ide/vscode-insiders.go +++ b/pkg/ide/vscode-insiders.go @@ -13,7 +13,7 @@ import ( "github.com/daytonaio/daytona/pkg/build/devcontainer" ) -func OpenVSCodeInsiders(activeProfile config.Profile, workspaceId string, projectName string, projectProviderMetadata string, gpgKey string) error { +func OpenVSCodeInsiders(activeProfile config.Profile, workspaceId string, workspaceProviderMetadata string, gpgKey *string) error { path, err := GetVSCodeInsidersBinaryPath() if err != nil { return err @@ -23,14 +23,14 @@ func OpenVSCodeInsiders(activeProfile config.Profile, workspaceId string, projec return err } - projectHostname := config.GetProjectHostname(activeProfile.Id, workspaceId, projectName) + workspaceHostname := config.GetHostname(activeProfile.Id, workspaceId) - projectDir, err := util.GetProjectDir(activeProfile, workspaceId, projectName, gpgKey) + workspaceDir, err := util.GetWorkspaceDir(activeProfile, workspaceId, gpgKey) if err != nil { return err } - commandArgument := fmt.Sprintf("vscode-remote://ssh-remote+%s/%s", projectHostname, projectDir) + commandArgument := fmt.Sprintf("vscode-remote://ssh-remote+%s/%s", workspaceHostname, workspaceDir) vscCommand := exec.Command(path, "--disable-extension", "ms-vscode-remote.remote-containers", "--folder-uri", commandArgument) @@ -39,11 +39,11 @@ func OpenVSCodeInsiders(activeProfile config.Profile, workspaceId string, projec return err } - if projectProviderMetadata == "" { + if workspaceProviderMetadata == "" { return nil } - return setupVSCodeCustomizations(projectHostname, projectProviderMetadata, devcontainer.Vscode, "*/.vscode-server-insiders/*/bin/code-server-insiders", "$HOME/.vscode-server-insiders/data/Machine/settings.json", ".daytona-customizations-lock-vscode-insiders") + return setupVSCodeCustomizations(workspaceHostname, workspaceProviderMetadata, devcontainer.Vscode, "*/.vscode-server-insiders/*/bin/code-server-insiders", "$HOME/.vscode-server-insiders/data/Machine/settings.json", ".daytona-customizations-lock-vscode-insiders") } func GetVSCodeInsidersBinaryPath() (string, error) { diff --git a/pkg/ide/vscode.go b/pkg/ide/vscode.go index 35fe0370f8..7b24441893 100644 --- a/pkg/ide/vscode.go +++ b/pkg/ide/vscode.go @@ -19,21 +19,21 @@ import ( log "github.com/sirupsen/logrus" ) -func OpenVSCode(activeProfile config.Profile, workspaceId string, projectName string, projectProviderMetadata string, gpgKey string) error { +func OpenVSCode(activeProfile config.Profile, workspaceId string, workspaceProviderMetadata string, gpgKey *string) error { CheckAndAlertVSCodeInstalled() err := installRemoteSSHExtension("code") if err != nil { return err } - projectHostname := config.GetProjectHostname(activeProfile.Id, workspaceId, projectName) + workspaceHostname := config.GetHostname(activeProfile.Id, workspaceId) - projectDir, err := util.GetProjectDir(activeProfile, workspaceId, projectName, gpgKey) + workspaceDir, err := util.GetWorkspaceDir(activeProfile, workspaceId, gpgKey) if err != nil { return err } - commandArgument := fmt.Sprintf("vscode-remote://ssh-remote+%s/%s", projectHostname, projectDir) + commandArgument := fmt.Sprintf("vscode-remote://ssh-remote+%s/%s", workspaceHostname, workspaceDir) vscCommand := exec.Command("code", "--disable-extension", "ms-vscode-remote.remote-containers", "--folder-uri", commandArgument) @@ -42,16 +42,16 @@ func OpenVSCode(activeProfile config.Profile, workspaceId string, projectName st return err } - if projectProviderMetadata == "" { + if workspaceProviderMetadata == "" { return nil } - return setupVSCodeCustomizations(projectHostname, projectProviderMetadata, devcontainer.Vscode, "*/.vscode-server/*/bin/code-server", "$HOME/.vscode-server/data/Machine/settings.json", ".daytona-customizations-lock-vscode") + return setupVSCodeCustomizations(workspaceHostname, workspaceProviderMetadata, devcontainer.Vscode, "*/.vscode-server/*/bin/code-server", "$HOME/.vscode-server/data/Machine/settings.json", ".daytona-customizations-lock-vscode") } -func setupVSCodeCustomizations(projectHostname string, projectProviderMetadata string, tool devcontainer.Tool, codeServerPath string, settingsPath string, lockFileName string) error { +func setupVSCodeCustomizations(workspaceHostname string, workspaceProviderMetadata string, tool devcontainer.Tool, codeServerPath string, settingsPath string, lockFileName string) error { // Check if customizations are already set up - err := exec.Command("ssh", projectHostname, "test", "-f", fmt.Sprintf("$HOME/%s-%s", lockFileName, string(tool))).Run() + err := exec.Command("ssh", workspaceHostname, "test", "-f", fmt.Sprintf("$HOME/%s-%s", lockFileName, string(tool))).Run() if err == nil { return nil } @@ -59,7 +59,7 @@ func setupVSCodeCustomizations(projectHostname string, projectProviderMetadata s fmt.Println("Setting up IDE customizations...") var metadata map[string]interface{} - if err := json.Unmarshal([]byte(projectProviderMetadata), &metadata); err != nil { + if err := json.Unmarshal([]byte(workspaceProviderMetadata), &metadata); err != nil { return err } @@ -94,7 +94,7 @@ func setupVSCodeCustomizations(projectHostname string, projectProviderMetadata s time.Sleep(2 * time.Second) // Wait for code to be installed var err error - if vscodePath, err = exec.Command("ssh", projectHostname, "find", "$HOME", "-path", fmt.Sprintf(`"%s"`, codeServerPath)).Output(); err == nil && len(vscodePath) > 0 { + if vscodePath, err = exec.Command("ssh", workspaceHostname, "find", "$HOME", "-path", fmt.Sprintf(`"%s"`, codeServerPath)).Output(); err == nil && len(vscodePath) > 0 { break } } @@ -106,7 +106,7 @@ func setupVSCodeCustomizations(projectHostname string, projectProviderMetadata s } args := []string{ - projectHostname, + workspaceHostname, strings.TrimRight(string(vscodePath), "\n"), "--accept-server-license-terms", } @@ -122,14 +122,14 @@ func setupVSCodeCustomizations(projectHostname string, projectProviderMetadata s } } - err := setupVSCodeSettings(projectHostname, mergedCustomizations, settingsPath) + err := setupVSCodeSettings(workspaceHostname, mergedCustomizations, settingsPath) if err != nil { log.Errorf("Failed to set IDE settings: %s", err) } } // Create lock file to indicate that customizations are set up - err = exec.Command("ssh", projectHostname, "touch", fmt.Sprintf("$HOME/%s-%s", lockFileName, string(tool))).Run() + err = exec.Command("ssh", workspaceHostname, "touch", fmt.Sprintf("$HOME/%s-%s", lockFileName, string(tool))).Run() if err != nil { return err } @@ -138,12 +138,12 @@ func setupVSCodeCustomizations(projectHostname string, projectProviderMetadata s return nil } -func setupVSCodeSettings(projectHostname string, customizations *devcontainer.Customizations, settingsPath string) error { +func setupVSCodeSettings(workspaceHostname string, customizations *devcontainer.Customizations, settingsPath string) error { if customizations == nil { return nil } - content, err := exec.Command("ssh", projectHostname, "cat", settingsPath).Output() + content, err := exec.Command("ssh", workspaceHostname, "cat", settingsPath).Output() if err != nil { content = []byte("{}") } @@ -170,7 +170,7 @@ func setupVSCodeSettings(projectHostname string, customizations *devcontainer.Cu return err } - err = exec.Command("ssh", projectHostname, "echo", fmt.Sprintf(`'%s'`, string(settingsJson)), ">", settingsPath).Run() + err = exec.Command("ssh", workspaceHostname, "echo", fmt.Sprintf(`'%s'`, string(settingsJson)), ">", settingsPath).Run() if err != nil { return err } diff --git a/pkg/ide/vscodium-insiders.go b/pkg/ide/vscodium-insiders.go index 214e72cdcc..1c6570398d 100644 --- a/pkg/ide/vscodium-insiders.go +++ b/pkg/ide/vscodium-insiders.go @@ -13,7 +13,7 @@ import ( "github.com/daytonaio/daytona/pkg/build/devcontainer" ) -func OpenVScodiumInsiders(activeProfile config.Profile, workspaceId string, projectName string, projectProviderMetadata string, gpgkey string) error { +func OpenVScodiumInsiders(activeProfile config.Profile, workspaceId string, workspaceProviderMetadata string, gpgkey *string) error { path, err := GetCodiumInsidersBinaryPath() if err != nil { return err @@ -23,14 +23,15 @@ func OpenVScodiumInsiders(activeProfile config.Profile, workspaceId string, proj if err != nil { return err } - projectHostname := config.GetProjectHostname(activeProfile.Id, workspaceId, projectName) - projectDir, err := util.GetProjectDir(activeProfile, workspaceId, projectName, gpgkey) + workspaceHostname := config.GetHostname(activeProfile.Id, workspaceId) + + workspaceDir, err := util.GetWorkspaceDir(activeProfile, workspaceId, gpgkey) if err != nil { return err } - commandArgument := fmt.Sprintf("vscode-remote://ssh-remote+%s/%s", projectHostname, projectDir) + commandArgument := fmt.Sprintf("vscode-remote://ssh-remote+%s/%s", workspaceHostname, workspaceDir) codiumInsidersCommand := exec.Command(path, "--disable-extension", "ms-vscode-remote.remote-containers", "--folder-uri", commandArgument) @@ -39,11 +40,11 @@ func OpenVScodiumInsiders(activeProfile config.Profile, workspaceId string, proj return err } - if projectProviderMetadata == "" { + if workspaceProviderMetadata == "" { return nil } - return setupVSCodeCustomizations(projectHostname, projectProviderMetadata, devcontainer.Vscode, "*/.vscodium-server-insiders/*/bin/codium-server-insiders", "$HOME/.vscodium-server-insiders/data/Machine/settings.json", ".daytona-customizations-lock-codium-insiders") + return setupVSCodeCustomizations(workspaceHostname, workspaceProviderMetadata, devcontainer.Vscode, "*/.vscodium-server-insiders/*/bin/codium-server-insiders", "$HOME/.vscodium-server-insiders/data/Machine/settings.json", ".daytona-customizations-lock-codium-insiders") } func GetCodiumInsidersBinaryPath() (string, error) { diff --git a/pkg/ide/vscodium.go b/pkg/ide/vscodium.go index b572da0f7a..0d17103dac 100644 --- a/pkg/ide/vscodium.go +++ b/pkg/ide/vscodium.go @@ -16,7 +16,7 @@ import ( const requiredExtension = "jeanp413.open-remote-ssh" -func OpenVScodium(activeProfile config.Profile, workspaceId string, projectName string, projectProviderMetadata string, gpgkey string) error { +func OpenVScodium(activeProfile config.Profile, workspaceId string, workspaceProviderMetadata string, gpgkey *string) error { path, err := GetCodiumBinaryPath() if err != nil { return err @@ -26,14 +26,15 @@ func OpenVScodium(activeProfile config.Profile, workspaceId string, projectName if err != nil { return err } - projectHostname := config.GetProjectHostname(activeProfile.Id, workspaceId, projectName) - projectDir, err := util.GetProjectDir(activeProfile, workspaceId, projectName, gpgkey) + workspaceHostname := config.GetHostname(activeProfile.Id, workspaceId) + + workspaceDir, err := util.GetWorkspaceDir(activeProfile, workspaceId, gpgkey) if err != nil { return err } - commandArgument := fmt.Sprintf("vscode-remote://ssh-remote+%s/%s", projectHostname, projectDir) + commandArgument := fmt.Sprintf("vscode-remote://ssh-remote+%s/%s", workspaceHostname, workspaceDir) codiumCommand := exec.Command(path, "--disable-extension", "ms-vscode-remote.remote-containers", "--folder-uri", commandArgument) @@ -42,11 +43,11 @@ func OpenVScodium(activeProfile config.Profile, workspaceId string, projectName return err } - if projectProviderMetadata == "" { + if workspaceProviderMetadata == "" { return nil } - return setupVSCodeCustomizations(projectHostname, projectProviderMetadata, devcontainer.Vscode, "*/.vscodium-server/*/bin/codium-server", "$HOME/.vscodium-server/data/Machine/settings.json", ".daytona-customizations-lock-codium") + return setupVSCodeCustomizations(workspaceHostname, workspaceProviderMetadata, devcontainer.Vscode, "*/.vscodium-server/*/bin/codium-server", "$HOME/.vscodium-server/data/Machine/settings.json", ".daytona-customizations-lock-codium") } func GetCodiumBinaryPath() (string, error) { diff --git a/pkg/ide/windsurf.go b/pkg/ide/windsurf.go index 7b511667a8..5f80faeda1 100644 --- a/pkg/ide/windsurf.go +++ b/pkg/ide/windsurf.go @@ -13,20 +13,20 @@ import ( "github.com/daytonaio/daytona/pkg/build/devcontainer" ) -func OpenWindsurf(activeProfile config.Profile, workspaceId string, projectName string, projectProviderMetadata string, gpgkey string) error { +func OpenWindsurf(activeProfile config.Profile, workspaceId string, workspaceProviderMetadata string, gpgkey *string) error { path, err := GetWindsurfBinaryPath() if err != nil { return err } - projectHostname := config.GetProjectHostname(activeProfile.Id, workspaceId, projectName) + workspaceHostname := config.GetHostname(activeProfile.Id, workspaceId) - projectDir, err := util.GetProjectDir(activeProfile, workspaceId, projectName, gpgkey) + workspaceDir, err := util.GetWorkspaceDir(activeProfile, workspaceId, gpgkey) if err != nil { return err } - commandArgument := fmt.Sprintf("vscode-remote://ssh-remote+%s/%s", projectHostname, projectDir) + commandArgument := fmt.Sprintf("vscode-remote://ssh-remote+%s/%s", workspaceHostname, workspaceDir) windsurfCommand := exec.Command(path, "--disable-extension", "ms-vscode-remote.remote-containers", "--folder-uri", commandArgument) @@ -35,11 +35,11 @@ func OpenWindsurf(activeProfile config.Profile, workspaceId string, projectName return err } - if projectProviderMetadata == "" { + if workspaceProviderMetadata == "" { return nil } - return setupVSCodeCustomizations(projectHostname, projectProviderMetadata, devcontainer.Vscode, "*/.windsurf-server/*/bin/windsurf-server", "$HOME/.windsurf-server/data/Machine/settings.json", ".daytona-customizations-lock-windsurf") + return setupVSCodeCustomizations(workspaceHostname, workspaceProviderMetadata, devcontainer.Vscode, "*/.windsurf-server/*/bin/windsurf-server", "$HOME/.windsurf-server/data/Machine/settings.json", ".daytona-customizations-lock-windsurf") } func GetWindsurfBinaryPath() (string, error) { diff --git a/pkg/ide/zed.go b/pkg/ide/zed.go index 6ef41598bd..e96d7a8385 100644 --- a/pkg/ide/zed.go +++ b/pkg/ide/zed.go @@ -14,19 +14,19 @@ import ( "github.com/daytonaio/daytona/pkg/views" ) -func OpenZed(activeProfile config.Profile, workspaceId, projectName, gpgKey string) error { +func OpenZed(activeProfile config.Profile, workspaceId string, gpgKey *string) error { path, err := GetZedBinaryPath() if err != nil { return err } - projectHostname := config.GetProjectHostname(activeProfile.Id, workspaceId, projectName) - projectDir, err := util.GetProjectDir(activeProfile, workspaceId, projectName, gpgKey) + workspaceHostname := config.GetHostname(activeProfile.Id, workspaceId) + workspaceDir, err := util.GetWorkspaceDir(activeProfile, workspaceId, gpgKey) if err != nil { return err } printDisclaimer() - zedCmd := exec.Command(path, fmt.Sprintf("ssh://%s%s", projectHostname, projectDir)) + zedCmd := exec.Command(path, fmt.Sprintf("ssh://%s%s", workspaceHostname, workspaceDir)) err = zedCmd.Run() if err != nil { diff --git a/pkg/jobs/build/build.go b/pkg/jobs/build/build.go new file mode 100644 index 0000000000..dee3e892ea --- /dev/null +++ b/pkg/jobs/build/build.go @@ -0,0 +1,43 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package build + +import ( + "context" + "errors" + + "github.com/daytonaio/daytona/pkg/build" + "github.com/daytonaio/daytona/pkg/logs" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/services" + "github.com/daytonaio/daytona/pkg/telemetry" +) + +type BuildJob struct { + models.Job + + findBuild func(ctx context.Context, buildId string) (*services.BuildDTO, error) + listSuccessfulBuilds func(ctx context.Context, repoUrl string) ([]*models.Build, error) + listConfigsForUrl func(ctx context.Context, repoUrl string) ([]*models.GitProviderConfig, error) + checkImageExists func(ctx context.Context, image string) bool + deleteImage func(ctx context.Context, image string, force bool) error + + trackTelemetryEvent func(event telemetry.Event, clientId string) error + loggerFactory logs.ILoggerFactory + builderFactory build.IBuilderFactory + + basePath string +} + +func (tj *BuildJob) Execute(ctx context.Context) error { + switch tj.Action { + case models.JobActionRun: + return tj.run(ctx, &tj.Job) + case models.JobActionDelete: + return tj.delete(ctx, &tj.Job, false) + case models.JobActionForceDelete: + return tj.delete(ctx, &tj.Job, true) + } + return errors.New("invalid job action") +} diff --git a/pkg/jobs/build/delete.go b/pkg/jobs/build/delete.go new file mode 100644 index 0000000000..9e2f2a7486 --- /dev/null +++ b/pkg/jobs/build/delete.go @@ -0,0 +1,23 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package build + +import ( + "context" + + "github.com/daytonaio/daytona/pkg/models" +) + +func (bj *BuildJob) delete(ctx context.Context, j *models.Job, force bool) error { + b, err := bj.findBuild(ctx, j.ResourceId) + if err != nil { + return err + } + + if b.Image != nil { + return bj.deleteImage(ctx, *b.Image, force) + } + + return nil +} diff --git a/pkg/jobs/build/factory.go b/pkg/jobs/build/factory.go new file mode 100644 index 0000000000..e4d0a16c42 --- /dev/null +++ b/pkg/jobs/build/factory.go @@ -0,0 +1,60 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package build + +import ( + "context" + + "github.com/daytonaio/daytona/pkg/build" + "github.com/daytonaio/daytona/pkg/jobs" + "github.com/daytonaio/daytona/pkg/logs" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/services" + "github.com/daytonaio/daytona/pkg/telemetry" +) + +type IBuildJobFactory interface { + Create(job models.Job) jobs.IJob +} + +type BuildJobFactory struct { + config BuildJobFactoryConfig +} + +type BuildJobFactoryConfig struct { + FindBuild func(ctx context.Context, buildId string) (*services.BuildDTO, error) + ListSuccessfulBuilds func(ctx context.Context, repoUrl string) ([]*models.Build, error) + ListConfigsForUrl func(ctx context.Context, repoUrl string) ([]*models.GitProviderConfig, error) + CheckImageExists func(ctx context.Context, image string) bool + DeleteImage func(ctx context.Context, image string, force bool) error + + TrackTelemetryEvent func(event telemetry.Event, clientId string) error + LoggerFactory logs.ILoggerFactory + BuilderFactory build.IBuilderFactory + + BasePath string +} + +func NewBuildJobFactory(config BuildJobFactoryConfig) IBuildJobFactory { + return &BuildJobFactory{ + config: config, + } +} + +func (f *BuildJobFactory) Create(job models.Job) jobs.IJob { + return &BuildJob{ + Job: job, + + findBuild: f.config.FindBuild, + listSuccessfulBuilds: f.config.ListSuccessfulBuilds, + listConfigsForUrl: f.config.ListConfigsForUrl, + checkImageExists: f.config.CheckImageExists, + deleteImage: f.config.DeleteImage, + + trackTelemetryEvent: f.config.TrackTelemetryEvent, + loggerFactory: f.config.LoggerFactory, + builderFactory: f.config.BuilderFactory, + basePath: f.config.BasePath, + } +} diff --git a/pkg/jobs/build/run.go b/pkg/jobs/build/run.go new file mode 100644 index 0000000000..49a279a9d9 --- /dev/null +++ b/pkg/jobs/build/run.go @@ -0,0 +1,140 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package build + +import ( + "context" + "fmt" + "path/filepath" + + "github.com/charmbracelet/lipgloss" + "github.com/daytonaio/daytona/pkg/build" + "github.com/daytonaio/daytona/pkg/git" + "github.com/daytonaio/daytona/pkg/logs" + "github.com/daytonaio/daytona/pkg/models" + "github.com/go-git/go-git/v5/plumbing/transport/http" +) + +func (bj *BuildJob) run(ctx context.Context, j *models.Job) error { + b, err := bj.findBuild(ctx, j.ResourceId) + if err != nil { + return err + } + + successfulBuilds, err := bj.listSuccessfulBuilds(ctx, b.Repository.Url) + if err != nil { + return err + } + + if b.BuildConfig == nil { + return fmt.Errorf("build config is not set") + } + + buildLogger, err := bj.loggerFactory.CreateLogger(b.Id, b.Id, logs.LogSourceBuilder) + if err != nil { + return err + } + defer buildLogger.Close() + + workspaceDir := filepath.Join(bj.basePath, b.Id, "workspace") + + builder, err := bj.builderFactory.Create(b.Build, workspaceDir) + if err != nil { + return bj.handleBuildResult(b.Build, builder, buildLogger, err) + } + + imageName, err := builder.GetImageName(b.Build) + if err != nil { + return bj.handleBuildResult(b.Build, builder, buildLogger, err) + } + + exists := bj.checkImageExists(ctx, imageName) + if exists { + return bj.handleBuildResult(b.Build, builder, buildLogger, nil) + } + + b.BuildConfig.CachedBuild = models.GetCachedBuild(&b.Build, successfulBuilds) + + err = bj.runBuildProcess(ctx, BuildProcessConfig{ + Builder: builder, + Build: &b.Build, + GitService: &git.Service{ + WorkspaceDir: workspaceDir, + LogWriter: buildLogger, + }, + }) + if err != nil { + return bj.handleBuildResult(b.Build, builder, buildLogger, err) + } + + buildLogger.Write([]byte("\n \n" + lipgloss.NewStyle().Bold(true).Render("Build run successful. Publishing..."))) + + err = builder.Publish(b.Build) + if err != nil { + return bj.handleBuildResult(b.Build, builder, buildLogger, err) + } + + err = builder.CleanUp() + if err != nil { + errMsg := fmt.Sprintf("Error cleaning up build: %s\n", err.Error()) + buildLogger.Write([]byte(errMsg + "\n")) + } + + return bj.handleBuildResult(b.Build, builder, buildLogger, err) +} + +type BuildProcessConfig struct { + Builder build.IBuilder + Build *models.Build + GitService git.IGitService +} + +func (bj *BuildJob) runBuildProcess(ctx context.Context, config BuildProcessConfig) error { + gitProviders, err := bj.listConfigsForUrl(ctx, config.Build.Repository.Url) + if err != nil { + return err + } + + var auth *http.BasicAuth + if len(gitProviders) > 0 { + auth = &http.BasicAuth{} + auth.Username = gitProviders[0].Username + auth.Password = gitProviders[0].Token + } + + err = config.GitService.CloneRepository(config.Build.Repository, auth) + if err != nil { + return err + } + + image, user, err := config.Builder.Build(*config.Build) + if err != nil { + return err + } + + config.Build.Image = &image + config.Build.User = &user + + return nil +} + +func (bj *BuildJob) handleBuildResult(b models.Build, builder build.IBuilder, buildLogger logs.Logger, err error) error { + var errMsg string + + if err != nil { + errMsg += "################################################\n" + errMsg += fmt.Sprintf("#### BUILD FAILED FOR %s: %s\n", b.Id, err.Error()) + errMsg += "################################################\n" + } + + if builder != nil { + cleanupErr := builder.CleanUp() + if cleanupErr != nil { + errMsg += fmt.Sprintf("Error cleaning up build: %s\n", cleanupErr.Error()) + } + } + + buildLogger.Write([]byte(errMsg + "\n")) + return err +} diff --git a/pkg/jobs/jobs.go b/pkg/jobs/jobs.go new file mode 100644 index 0000000000..9501a84b48 --- /dev/null +++ b/pkg/jobs/jobs.go @@ -0,0 +1,12 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package jobs + +import ( + "context" +) + +type IJob interface { + Execute(ctx context.Context) error +} diff --git a/pkg/jobs/runner/factory.go b/pkg/jobs/runner/factory.go new file mode 100644 index 0000000000..742b575221 --- /dev/null +++ b/pkg/jobs/runner/factory.go @@ -0,0 +1,38 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package runner + +import ( + "github.com/daytonaio/daytona/pkg/jobs" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/runner/providermanager" + "github.com/daytonaio/daytona/pkg/telemetry" +) + +type IRunnerJobFactory interface { + Create(job models.Job) jobs.IJob +} + +type RunnerJobFactory struct { + config RunnerJobFactoryConfig +} + +type RunnerJobFactoryConfig struct { + TrackTelemetryEvent func(event telemetry.Event, clientId string) error + ProviderManager providermanager.IProviderManager +} + +func NewRunnerJobFactory(config RunnerJobFactoryConfig) IRunnerJobFactory { + return &RunnerJobFactory{ + config: config, + } +} + +func (f *RunnerJobFactory) Create(job models.Job) jobs.IJob { + return &RunnerJob{ + Job: job, + trackTelemetryEvent: f.config.TrackTelemetryEvent, + providerManager: f.config.ProviderManager, + } +} diff --git a/pkg/jobs/runner/install.go b/pkg/jobs/runner/install.go new file mode 100644 index 0000000000..a2d86d9922 --- /dev/null +++ b/pkg/jobs/runner/install.go @@ -0,0 +1,32 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package runner + +import ( + "context" + "encoding/json" + "errors" + + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/services" +) + +func (rj *RunnerJob) installProvider(ctx context.Context, j *models.Job) error { + if j.Metadata == nil { + return errors.New("metadata is required") + } + + var providerJobMetadata services.ProviderMetadata + err := json.Unmarshal([]byte(*j.Metadata), &providerJobMetadata) + if err != nil { + return err + } + + downloadPath, err := rj.providerManager.DownloadProvider(ctx, providerJobMetadata.DownloadUrls, providerJobMetadata.Name) + if err != nil { + return err + } + + return rj.providerManager.RegisterProvider(downloadPath, false) +} diff --git a/pkg/jobs/runner/runner.go b/pkg/jobs/runner/runner.go new file mode 100644 index 0000000000..4a40b913c6 --- /dev/null +++ b/pkg/jobs/runner/runner.go @@ -0,0 +1,32 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package runner + +import ( + "context" + "errors" + + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/runner/providermanager" + "github.com/daytonaio/daytona/pkg/telemetry" +) + +type RunnerJob struct { + models.Job + + trackTelemetryEvent func(event telemetry.Event, clientId string) error + providerManager providermanager.IProviderManager +} + +func (pj *RunnerJob) Execute(ctx context.Context) error { + switch pj.Action { + case models.JobActionInstallProvider: + return pj.installProvider(ctx, &pj.Job) + case models.JobActionUpdateProvider: + return pj.updateProvider(ctx, &pj.Job) + case models.JobActionUninstallProvider: + return pj.uninstallProvider(ctx, &pj.Job) + } + return errors.New("invalid job action") +} diff --git a/pkg/jobs/runner/uninstall.go b/pkg/jobs/runner/uninstall.go new file mode 100644 index 0000000000..d684e9c965 --- /dev/null +++ b/pkg/jobs/runner/uninstall.go @@ -0,0 +1,19 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package runner + +import ( + "context" + "errors" + + "github.com/daytonaio/daytona/pkg/models" +) + +func (rj *RunnerJob) uninstallProvider(_ context.Context, j *models.Job) error { + if j.Metadata == nil { + return errors.New("metadata is required") + } + + return rj.providerManager.UninstallProvider(*j.Metadata) +} diff --git a/pkg/jobs/runner/update.go b/pkg/jobs/runner/update.go new file mode 100644 index 0000000000..a6af02e1b5 --- /dev/null +++ b/pkg/jobs/runner/update.go @@ -0,0 +1,38 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package runner + +import ( + "context" + "encoding/json" + "errors" + + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/services" +) + +func (pj *RunnerJob) updateProvider(ctx context.Context, j *models.Job) error { + if j.Metadata == nil { + return errors.New("metadata is required") + } + + installMetadata := j.Metadata + + var metadata services.ProviderMetadata + err := json.Unmarshal([]byte(*j.Metadata), &metadata) + if err != nil { + return err + } + + j.Metadata = &metadata.Name + + err = pj.uninstallProvider(ctx, j) + if err != nil { + return err + } + + j.Metadata = installMetadata + + return pj.installProvider(ctx, j) +} diff --git a/pkg/jobs/target/create.go b/pkg/jobs/target/create.go new file mode 100644 index 0000000000..ac1852546c --- /dev/null +++ b/pkg/jobs/target/create.go @@ -0,0 +1,54 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package target + +import ( + "context" + "fmt" + + "github.com/daytonaio/daytona/pkg/logs" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/provider" + "github.com/daytonaio/daytona/pkg/views" +) + +func (tj *TargetJob) create(ctx context.Context, j *models.Job) error { + tg, err := tj.findTarget(ctx, j.ResourceId) + if err != nil { + return err + } + + targetLogger, err := tj.loggerFactory.CreateLogger(tg.Id, tg.Name, logs.LogSourceServer) + if err != nil { + return err + } + defer targetLogger.Close() + + targetLogger.Write([]byte(fmt.Sprintf("Creating target %s (%s)\n", tg.Name, tg.Id))) + + p, err := tj.providerManager.GetProvider(tg.TargetConfig.ProviderInfo.Name) + if err != nil { + return err + } + + _, err = (*p).CreateTarget(&provider.TargetRequest{ + Target: tg, + }) + if err != nil { + return err + } + + err = tj.handleSuccessfulCreation(ctx, tg.Id) + if err != nil { + return err + } + + targetLogger.Write([]byte(views.GetPrettyLogLine("Target creation complete"))) + + if tg.TargetConfig.ProviderInfo.AgentlessTarget { + return nil + } + + return tj.start(ctx, j) +} diff --git a/pkg/jobs/target/delete.go b/pkg/jobs/target/delete.go new file mode 100644 index 0000000000..b9c67eb2a4 --- /dev/null +++ b/pkg/jobs/target/delete.go @@ -0,0 +1,59 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package target + +import ( + "context" + "fmt" + + "github.com/daytonaio/daytona/pkg/logs" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/provider" + log "github.com/sirupsen/logrus" +) + +func (tj *TargetJob) delete(ctx context.Context, j *models.Job, force bool) error { + t, err := tj.findTarget(ctx, j.ResourceId) + if err != nil { + return err + } + + targetLogger, err := tj.loggerFactory.CreateLogger(t.Id, t.Name, logs.LogSourceServer) + if err != nil { + return err + } + defer targetLogger.Close() + + targetLogger.Write([]byte(fmt.Sprintf("Destroying target %s", t.Name))) + + p, err := tj.providerManager.GetProvider(t.TargetConfig.ProviderInfo.Name) + if err != nil { + if force { + log.Error(err) + return nil + } + return err + } + + _, err = (*p).DestroyTarget(&provider.TargetRequest{ + Target: t, + }) + if err != nil { + if force { + log.Error(err) + return nil + } + return err + } + + targetLogger.Write([]byte(fmt.Sprintf("Target %s destroyed", t.Name))) + + err = targetLogger.Cleanup() + if err != nil { + // Should not fail the whole operation if the target logger cannot be cleaned up + log.Error(err) + } + + return nil +} diff --git a/pkg/jobs/target/factory.go b/pkg/jobs/target/factory.go new file mode 100644 index 0000000000..52209c6aeb --- /dev/null +++ b/pkg/jobs/target/factory.go @@ -0,0 +1,52 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package target + +import ( + "context" + + "github.com/daytonaio/daytona/pkg/jobs" + "github.com/daytonaio/daytona/pkg/logs" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/runner/providermanager" + "github.com/daytonaio/daytona/pkg/telemetry" +) + +type ITargetJobFactory interface { + Create(job models.Job) jobs.IJob +} + +type TargetJobFactory struct { + config TargetJobFactoryConfig +} + +type TargetJobFactoryConfig struct { + FindTarget func(ctx context.Context, targetId string) (*models.Target, error) + HandleSuccessfulCreation func(ctx context.Context, targetId string) error + + TrackTelemetryEvent func(event telemetry.Event, clientId string) error + UpdateTargetProviderMetadata func(ctx context.Context, targetId, metadata string) error + + LoggerFactory logs.ILoggerFactory + ProviderManager providermanager.IProviderManager +} + +func NewTargetJobFactory(config TargetJobFactoryConfig) ITargetJobFactory { + return &TargetJobFactory{ + config: config, + } +} + +func (f *TargetJobFactory) Create(job models.Job) jobs.IJob { + return &TargetJob{ + Job: job, + + findTarget: f.config.FindTarget, + handleSuccessfulCreation: f.config.HandleSuccessfulCreation, + trackTelemetryEvent: f.config.TrackTelemetryEvent, + updateTargetProviderMetadata: f.config.UpdateTargetProviderMetadata, + loggerFactory: f.config.LoggerFactory, + providerManager: f.config.ProviderManager, + } +} diff --git a/pkg/jobs/target/restart.go b/pkg/jobs/target/restart.go new file mode 100644 index 0000000000..c112d592fa --- /dev/null +++ b/pkg/jobs/target/restart.go @@ -0,0 +1,19 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package target + +import ( + "context" + + "github.com/daytonaio/daytona/pkg/models" +) + +func (tj *TargetJob) restart(ctx context.Context, j *models.Job) error { + err := tj.stop(ctx, j) + if err != nil { + return err + } + + return tj.start(ctx, j) +} diff --git a/pkg/jobs/target/start.go b/pkg/jobs/target/start.go new file mode 100644 index 0000000000..06c8c7f604 --- /dev/null +++ b/pkg/jobs/target/start.go @@ -0,0 +1,56 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package target + +import ( + "context" + "fmt" + + "github.com/daytonaio/daytona/pkg/logs" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/provider" + "github.com/daytonaio/daytona/pkg/views" +) + +func (tj *TargetJob) start(ctx context.Context, j *models.Job) error { + tg, err := tj.findTarget(ctx, j.ResourceId) + if err != nil { + return err + } + + targetLogger, err := tj.loggerFactory.CreateLogger(tg.Id, tg.Name, logs.LogSourceServer) + if err != nil { + return err + } + defer targetLogger.Close() + + targetLogger.Write([]byte("Starting target\n")) + + p, err := tj.providerManager.GetProvider(tg.TargetConfig.ProviderInfo.Name) + if err != nil { + return err + } + + _, err = (*p).StartTarget(&provider.TargetRequest{ + Target: tg, + }) + if err != nil { + return err + } + + providerMetadata, err := (*p).GetTargetProviderMetadata(&provider.TargetRequest{ + Target: tg, + }) + if err != nil { + return err + } + + err = tj.updateTargetProviderMetadata(ctx, tg.Id, providerMetadata) + if err != nil { + return err + } + + targetLogger.Write([]byte(views.GetPrettyLogLine(fmt.Sprintf("Target %s started", tg.Name)))) + return nil +} diff --git a/pkg/jobs/target/stop.go b/pkg/jobs/target/stop.go new file mode 100644 index 0000000000..6a8dc38271 --- /dev/null +++ b/pkg/jobs/target/stop.go @@ -0,0 +1,45 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package target + +import ( + "context" + "fmt" + + "github.com/daytonaio/daytona/pkg/logs" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/provider" + "github.com/daytonaio/daytona/pkg/views" +) + +func (tj *TargetJob) stop(ctx context.Context, j *models.Job) error { + t, err := tj.findTarget(ctx, j.ResourceId) + if err != nil { + return err + } + + targetLogger, err := tj.loggerFactory.CreateLogger(t.Id, t.Name, logs.LogSourceServer) + if err != nil { + return err + } + defer targetLogger.Close() + + targetLogger.Write([]byte(fmt.Sprintf("Stopping target %s\n", t.Name))) + + p, err := tj.providerManager.GetProvider(t.TargetConfig.ProviderInfo.Name) + if err != nil { + return err + } + + _, err = (*p).StopTarget(&provider.TargetRequest{ + Target: t, + }) + if err != nil { + return err + } + + targetLogger.Write([]byte(views.GetPrettyLogLine(fmt.Sprintf("Target %s stopped", t.Name)))) + + return nil +} diff --git a/pkg/jobs/target/target.go b/pkg/jobs/target/target.go new file mode 100644 index 0000000000..bb6d7d8447 --- /dev/null +++ b/pkg/jobs/target/target.go @@ -0,0 +1,45 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package target + +import ( + "context" + "errors" + + "github.com/daytonaio/daytona/pkg/logs" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/runner/providermanager" + "github.com/daytonaio/daytona/pkg/telemetry" +) + +type TargetJob struct { + models.Job + + findTarget func(ctx context.Context, targetId string) (*models.Target, error) + handleSuccessfulCreation func(ctx context.Context, targetId string) error + + trackTelemetryEvent func(event telemetry.Event, clientId string) error + updateTargetProviderMetadata func(ctx context.Context, targetId, metadata string) error + + loggerFactory logs.ILoggerFactory + providerManager providermanager.IProviderManager +} + +func (tj *TargetJob) Execute(ctx context.Context) error { + switch tj.Action { + case models.JobActionCreate: + return tj.create(ctx, &tj.Job) + case models.JobActionStart: + return tj.start(ctx, &tj.Job) + case models.JobActionStop: + return tj.stop(ctx, &tj.Job) + case models.JobActionRestart: + return tj.restart(ctx, &tj.Job) + case models.JobActionDelete: + return tj.delete(ctx, &tj.Job, false) + case models.JobActionForceDelete: + return tj.delete(ctx, &tj.Job, true) + } + return errors.New("invalid job action") +} diff --git a/pkg/jobs/workspace/create.go b/pkg/jobs/workspace/create.go new file mode 100644 index 0000000000..03159633f9 --- /dev/null +++ b/pkg/jobs/workspace/create.go @@ -0,0 +1,67 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package workspace + +import ( + "context" + "fmt" + + "github.com/daytonaio/daytona/pkg/common" + "github.com/daytonaio/daytona/pkg/logs" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/provider" + "github.com/daytonaio/daytona/pkg/stores" + "github.com/daytonaio/daytona/pkg/views" +) + +func (wj *WorkspaceJob) create(ctx context.Context, j *models.Job) error { + w, err := wj.findWorkspace(ctx, j.ResourceId) + if err != nil { + return err + } + + workspaceLogger, err := wj.loggerFactory.CreateLogger(w.Id, w.Name, logs.LogSourceServer) + if err != nil { + return err + } + defer workspaceLogger.Close() + + workspaceLogger.Write([]byte(fmt.Sprintf("Creating workspace %s (%s)\n", w.Name, w.Id))) + + workspaceEnvVars, err := wj.getWorkspaceEnvironmentVariables(ctx, w) + if err != nil { + return err + } + + var gc *models.GitProviderConfig + + if w.GitProviderConfigId != nil { + gc, err = wj.findGitProviderConfig(ctx, *w.GitProviderConfigId) + if err != nil && !stores.IsGitProviderNotFound(err) { + return err + } + } + + extractedEnvVars, containerRegistries := common.ExtractContainerRegistryFromEnvVars(workspaceEnvVars) + + w.EnvVars = extractedEnvVars + + p, err := wj.providerManager.GetProvider(w.Target.TargetConfig.ProviderInfo.Name) + if err != nil { + return err + } + + _, err = (*p).CreateWorkspace(&provider.WorkspaceRequest{ + Workspace: w, + ContainerRegistries: containerRegistries, + GitProviderConfig: gc, + BuilderImage: wj.builderImage, + }) + if err != nil { + return err + } + + workspaceLogger.Write([]byte(views.GetPrettyLogLine(fmt.Sprintf("Workspace %s created", w.Name)))) + return wj.start(ctx, j) +} diff --git a/pkg/jobs/workspace/delete.go b/pkg/jobs/workspace/delete.go new file mode 100644 index 0000000000..5c2b39e156 --- /dev/null +++ b/pkg/jobs/workspace/delete.go @@ -0,0 +1,58 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package workspace + +import ( + "context" + "fmt" + + "github.com/daytonaio/daytona/pkg/logs" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/provider" + log "github.com/sirupsen/logrus" +) + +func (wj *WorkspaceJob) delete(ctx context.Context, j *models.Job, force bool) error { + w, err := wj.findWorkspace(ctx, j.ResourceId) + if err != nil { + return err + } + + workspaceLogger, err := wj.loggerFactory.CreateLogger(w.Id, w.Name, logs.LogSourceServer) + if err != nil { + return err + } + defer workspaceLogger.Close() + + workspaceLogger.Write([]byte(fmt.Sprintf("Destroying workspace %s", w.Name))) + + p, err := wj.providerManager.GetProvider(w.Target.TargetConfig.ProviderInfo.Name) + if err != nil { + if force { + log.Error(err) + return nil + } + return err + } + + _, err = (*p).DestroyWorkspace(&provider.WorkspaceRequest{ + Workspace: w, + }) + if err != nil { + if force { + log.Error(err) + } + return nil + } + + workspaceLogger.Write([]byte(fmt.Sprintf("Workspace %s destroyed", w.Name))) + + err = workspaceLogger.Cleanup() + if err != nil { + // Should not fail the whole operation if the workspace logger cannot be cleaned up + log.Error(err) + } + + return nil +} diff --git a/pkg/jobs/workspace/factory.go b/pkg/jobs/workspace/factory.go new file mode 100644 index 0000000000..d08ee90758 --- /dev/null +++ b/pkg/jobs/workspace/factory.go @@ -0,0 +1,57 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package workspace + +import ( + "context" + + "github.com/daytonaio/daytona/pkg/jobs" + "github.com/daytonaio/daytona/pkg/logs" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/runner/providermanager" + "github.com/daytonaio/daytona/pkg/telemetry" +) + +type IWorkspaceJobFactory interface { + Create(job models.Job) jobs.IJob +} + +type WorkspaceJobFactory struct { + config WorkspaceJobFactoryConfig +} + +type WorkspaceJobFactoryConfig struct { + FindWorkspace func(ctx context.Context, workspaceId string) (*models.Workspace, error) + FindTarget func(ctx context.Context, targetId string) (*models.Target, error) + FindGitProviderConfig func(ctx context.Context, id string) (*models.GitProviderConfig, error) + GetWorkspaceEnvironmentVariables func(ctx context.Context, w *models.Workspace) (map[string]string, error) + UpdateWorkspaceProviderMetadata func(ctx context.Context, workspaceId, metadata string) error + TrackTelemetryEvent func(event telemetry.Event, clientId string) error + + LoggerFactory logs.ILoggerFactory + ProviderManager providermanager.IProviderManager + BuilderImage string +} + +func NewWorkspaceJobFactory(config WorkspaceJobFactoryConfig) IWorkspaceJobFactory { + return &WorkspaceJobFactory{ + config: config, + } +} + +func (f *WorkspaceJobFactory) Create(job models.Job) jobs.IJob { + return &WorkspaceJob{ + Job: job, + + findWorkspace: f.config.FindWorkspace, + findTarget: f.config.FindTarget, + findGitProviderConfig: f.config.FindGitProviderConfig, + getWorkspaceEnvironmentVariables: f.config.GetWorkspaceEnvironmentVariables, + updateWorkspaceProviderMetadata: f.config.UpdateWorkspaceProviderMetadata, + trackTelemetryEvent: f.config.TrackTelemetryEvent, + loggerFactory: f.config.LoggerFactory, + providerManager: f.config.ProviderManager, + builderImage: f.config.BuilderImage, + } +} diff --git a/pkg/jobs/workspace/restart.go b/pkg/jobs/workspace/restart.go new file mode 100644 index 0000000000..ec4a907e51 --- /dev/null +++ b/pkg/jobs/workspace/restart.go @@ -0,0 +1,19 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package workspace + +import ( + "context" + + "github.com/daytonaio/daytona/pkg/models" +) + +func (wj *WorkspaceJob) restart(ctx context.Context, j *models.Job) error { + err := wj.stop(ctx, j) + if err != nil { + return err + } + + return wj.start(ctx, j) +} diff --git a/pkg/jobs/workspace/start.go b/pkg/jobs/workspace/start.go new file mode 100644 index 0000000000..81fc468c42 --- /dev/null +++ b/pkg/jobs/workspace/start.go @@ -0,0 +1,79 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package workspace + +import ( + "context" + "fmt" + + "github.com/daytonaio/daytona/pkg/common" + "github.com/daytonaio/daytona/pkg/logs" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/provider" + "github.com/daytonaio/daytona/pkg/stores" + "github.com/daytonaio/daytona/pkg/views" +) + +func (wj *WorkspaceJob) start(ctx context.Context, j *models.Job) error { + w, err := wj.findWorkspace(ctx, j.ResourceId) + if err != nil { + return err + } + + workspaceLogger, err := wj.loggerFactory.CreateLogger(w.Id, w.Name, logs.LogSourceServer) + if err != nil { + return err + } + defer workspaceLogger.Close() + + workspaceLogger.Write([]byte(fmt.Sprintf("Starting workspace %s\n", w.Name))) + + workspaceEnvVars, err := wj.getWorkspaceEnvironmentVariables(ctx, w) + if err != nil { + return err + } + + var gc *models.GitProviderConfig + + if w.GitProviderConfigId != nil { + gc, err = wj.findGitProviderConfig(ctx, *w.GitProviderConfigId) + if err != nil && !stores.IsGitProviderNotFound(err) { + return err + } + } + + extractedEnvVars, containerRegistries := common.ExtractContainerRegistryFromEnvVars(workspaceEnvVars) + + w.EnvVars = extractedEnvVars + + p, err := wj.providerManager.GetProvider(w.Target.TargetConfig.ProviderInfo.Name) + if err != nil { + return err + } + + req := &provider.WorkspaceRequest{ + Workspace: w, + ContainerRegistries: containerRegistries, + GitProviderConfig: gc, + BuilderImage: wj.builderImage, + } + + _, err = (*p).StartWorkspace(req) + if err != nil { + return err + } + + providerMetadata, err := (*p).GetWorkspaceProviderMetadata(req) + if err != nil { + return err + } + + err = wj.updateWorkspaceProviderMetadata(ctx, w.Id, providerMetadata) + if err != nil { + return err + } + + workspaceLogger.Write([]byte(views.GetPrettyLogLine(fmt.Sprintf("Workspace %s started", w.Name)))) + return nil +} diff --git a/pkg/jobs/workspace/stop.go b/pkg/jobs/workspace/stop.go new file mode 100644 index 0000000000..37c310b23d --- /dev/null +++ b/pkg/jobs/workspace/stop.go @@ -0,0 +1,45 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package workspace + +import ( + "context" + "fmt" + + "github.com/daytonaio/daytona/pkg/logs" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/provider" + "github.com/daytonaio/daytona/pkg/views" +) + +func (wj *WorkspaceJob) stop(ctx context.Context, j *models.Job) error { + w, err := wj.findWorkspace(ctx, j.ResourceId) + if err != nil { + return err + } + + workspaceLogger, err := wj.loggerFactory.CreateLogger(w.Id, w.Name, logs.LogSourceServer) + if err != nil { + return err + } + defer workspaceLogger.Close() + + workspaceLogger.Write([]byte(fmt.Sprintf("Stopping workspace %s\n", w.Name))) + + p, err := wj.providerManager.GetProvider(w.Target.TargetConfig.ProviderInfo.Name) + if err != nil { + return err + } + + _, err = (*p).StopWorkspace(&provider.WorkspaceRequest{ + Workspace: w, + }) + if err != nil { + return err + } + + workspaceLogger.Write([]byte(views.GetPrettyLogLine(fmt.Sprintf("Workspace %s stopped", w.Name)))) + + return nil +} diff --git a/pkg/jobs/workspace/workspace.go b/pkg/jobs/workspace/workspace.go new file mode 100644 index 0000000000..c85baad2c2 --- /dev/null +++ b/pkg/jobs/workspace/workspace.go @@ -0,0 +1,47 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package workspace + +import ( + "context" + "errors" + + "github.com/daytonaio/daytona/pkg/logs" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/runner/providermanager" + "github.com/daytonaio/daytona/pkg/telemetry" +) + +type WorkspaceJob struct { + models.Job + + findWorkspace func(ctx context.Context, workspaceId string) (*models.Workspace, error) + findTarget func(ctx context.Context, targetId string) (*models.Target, error) + findGitProviderConfig func(ctx context.Context, id string) (*models.GitProviderConfig, error) + updateWorkspaceProviderMetadata func(ctx context.Context, workspaceId, metadata string) error + getWorkspaceEnvironmentVariables func(ctx context.Context, w *models.Workspace) (map[string]string, error) + trackTelemetryEvent func(event telemetry.Event, clientId string) error + + loggerFactory logs.ILoggerFactory + providerManager providermanager.IProviderManager + builderImage string +} + +func (wj *WorkspaceJob) Execute(ctx context.Context) error { + switch wj.Action { + case models.JobActionCreate: + return wj.create(ctx, &wj.Job) + case models.JobActionStart: + return wj.start(ctx, &wj.Job) + case models.JobActionStop: + return wj.stop(ctx, &wj.Job) + case models.JobActionRestart: + return wj.restart(ctx, &wj.Job) + case models.JobActionDelete: + return wj.delete(ctx, &wj.Job, false) + case models.JobActionForceDelete: + return wj.delete(ctx, &wj.Job, true) + } + return errors.New("invalid job action") +} diff --git a/pkg/logs/build.go b/pkg/logs/build.go deleted file mode 100644 index 77ad0e3ec7..0000000000 --- a/pkg/logs/build.go +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package logs - -import ( - "encoding/json" - "io" - "os" - "path/filepath" - - "github.com/sirupsen/logrus" -) - -type buildLogger struct { - logsDir string - buildId string - logFile *os.File - logger *logrus.Logger - source LogSource -} - -func (bl *buildLogger) Write(p []byte) (n int, err error) { - if bl.logFile == nil { - filePath := filepath.Join(bl.logsDir, bl.buildId, "log") - err = os.MkdirAll(filepath.Dir(filePath), 0755) - if err != nil { - return len(p), err - } - - logFile, err := os.OpenFile(filePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) - if err != nil { - return len(p), err - } - bl.logFile = logFile - bl.logger.SetOutput(bl.logFile) - } - - var entry LogEntry - entry.Msg = string(p) - entry.Source = string(bl.source) - entry.BuildId = &bl.buildId - - b, err := json.Marshal(entry) - if err != nil { - return len(p), err - } - - b = append(b, []byte(LogDelimiter)...) - - _, err = bl.logFile.Write(b) - if err != nil { - return len(p), err - } - - return len(p), nil -} - -func (bl *buildLogger) Close() error { - if bl.logFile != nil { - err := bl.logFile.Close() - bl.logFile = nil - return err - } - return nil -} - -func (bl *buildLogger) Cleanup() error { - buildLogsDir := filepath.Join(bl.logsDir, bl.buildId) - - _, err := os.Stat(buildLogsDir) - if os.IsNotExist(err) { - return nil - } else if err != nil { - return err - } - - return os.RemoveAll(buildLogsDir) -} - -func (l *loggerFactoryImpl) CreateBuildLogger(buildId string, source LogSource) Logger { - logger := logrus.New() - - return &buildLogger{ - logsDir: l.buildLogsDir, - buildId: buildId, - logger: logger, - source: source, - } -} - -func (l *loggerFactoryImpl) CreateBuildLogReader(buildId string) (io.Reader, error) { - filePath := filepath.Join(l.buildLogsDir, buildId, "log") - return os.Open(filePath) -} diff --git a/pkg/logs/factory.go b/pkg/logs/factory.go new file mode 100644 index 0000000000..5037a47f04 --- /dev/null +++ b/pkg/logs/factory.go @@ -0,0 +1,98 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package logs + +import ( + "fmt" + "io" + "os" + "path/filepath" +) + +var LogDelimiter = "!-#_^*|\n" + +type Logger interface { + io.WriteCloser + ConstructJsonLogEntry(p []byte) ([]byte, error) + Cleanup() error +} + +type LogSource string + +const ( + LogSourceServer LogSource = "server" + LogSourceProvider LogSource = "provider" + LogSourceBuilder LogSource = "builder" + LogSourceRunner LogSource = "runner" +) + +type LogEntry struct { + Source string `json:"source"` + Label string `json:"label"` + Msg string `json:"msg"` + Level string `json:"level"` + Time string `json:"time"` +} + +type ILoggerFactory interface { + CreateLogger(id, label string, source LogSource) (Logger, error) + CreateLogReader(id string) (io.Reader, error) + CreateLogWriter(id string) (io.WriteCloser, error) +} + +type loggerFactory struct { + logsDir string +} + +type LoggerFactoryConfig struct { + LogsDir string + ApiUrl *string + ApiKey *string + ApiBasePath *ApiBasePath +} + +func NewLoggerFactory(config LoggerFactoryConfig) ILoggerFactory { + if config.ApiUrl != nil && config.ApiKey != nil && config.ApiBasePath != nil { + return &remoteLoggerFactory{ + localLoggerFactory: &loggerFactory{ + logsDir: config.LogsDir, + }, + apiUrl: *config.ApiUrl, + apiKey: *config.ApiKey, + apiBasePath: *config.ApiBasePath, + } + } + + return &loggerFactory{ + logsDir: config.LogsDir, + } +} + +func (l *loggerFactory) CreateLogger(id, label string, source LogSource) (Logger, error) { + return &logger{ + id: id, + logsDir: l.logsDir, + label: label, + source: source, + }, nil +} + +func (l *loggerFactory) CreateLogReader(id string) (io.Reader, error) { + filePath := filepath.Join(l.logsDir, id, "log") + + dirPath := filepath.Dir(filePath) + if err := os.MkdirAll(dirPath, 0755); err != nil { + return nil, fmt.Errorf("failed to create directories for path %s: %v", dirPath, err) + } + + return os.OpenFile(filePath, os.O_RDONLY|os.O_CREATE, 0644) +} + +func (l *loggerFactory) CreateLogWriter(id string) (io.WriteCloser, error) { + return &logger{ + id: id, + logsDir: l.logsDir, + skipEntryConstructor: true, + }, nil +} diff --git a/internal/util/log_reader.go b/pkg/logs/log_reader.go similarity index 88% rename from internal/util/log_reader.go rename to pkg/logs/log_reader.go index 1791f641dd..9a6ef38d4e 100644 --- a/internal/util/log_reader.go +++ b/pkg/logs/log_reader.go @@ -1,7 +1,7 @@ // Copyright 2024 Daytona Platforms Inc. // SPDX-License-Identifier: Apache-2.0 -package util +package logs import ( "archive/zip" @@ -12,8 +12,6 @@ import ( "io" "strings" - "github.com/daytonaio/daytona/pkg/logs" - log "github.com/sirupsen/logrus" ) @@ -50,8 +48,8 @@ func ReadJSONLog(ctx context.Context, logReader io.Reader, follow bool, c chan i default: line, readErr := reader.ReadString('\n') if line != "" { - stripped := strings.TrimSuffix(line, logs.LogDelimiter) - var logEntry logs.LogEntry + stripped := strings.TrimSuffix(line, LogDelimiter) + var logEntry LogEntry err := json.Unmarshal([]byte(stripped), &logEntry) if err != nil { @@ -62,10 +60,10 @@ func ReadJSONLog(ctx context.Context, logReader io.Reader, follow bool, c chan i } if readErr != nil { if readErr != io.EOF { - c <- logs.LogEntry{} + c <- LogEntry{} errChan <- readErr } else if !follow { - c <- logs.LogEntry{} + c <- LogEntry{} errChan <- io.EOF return } diff --git a/pkg/logs/logger.go b/pkg/logs/logger.go index 8fa7c28333..0eb4215e4d 100644 --- a/pkg/logs/logger.go +++ b/pkg/logs/logger.go @@ -4,58 +4,86 @@ package logs import ( - "io" + "encoding/json" + "os" + "path/filepath" + "time" ) -var LogDelimiter = "!-#_^*|\n" - -type Logger interface { - io.WriteCloser - Cleanup() error +type logger struct { + logsDir string + id string + label string + logFile *os.File + source LogSource + skipEntryConstructor bool } -type LogSource string +func (w *logger) Write(p []byte) (n int, err error) { + if w.logFile == nil { + filePath := filepath.Join(w.logsDir, w.id, "log") + err = os.MkdirAll(filepath.Dir(filePath), 0755) + if err != nil { + return len(p), err + } -const ( - LogSourceServer LogSource = "server" - LogSourceProvider LogSource = "provider" - LogSourceBuilder LogSource = "builder" -) + logFile, err := os.OpenFile(filePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + if err != nil { + return len(p), err + } + w.logFile = logFile + } -type LogEntry struct { - Source string `json:"source"` - WorkspaceId *string `json:"workspaceId,omitempty"` - ProjectName *string `json:"projectName,omitempty"` - BuildId *string `json:"buildId,omitempty"` - Msg string `json:"msg"` - Level string `json:"level"` - Time string `json:"time"` -} + b := p -type LoggerFactory interface { - CreateWorkspaceLogger(workspaceId string, source LogSource) Logger - CreateProjectLogger(workspaceId, projectName string, source LogSource) Logger - CreateBuildLogger(buildId string, source LogSource) Logger - CreateWorkspaceLogReader(workspaceId string) (io.Reader, error) - CreateProjectLogReader(workspaceId, projectName string) (io.Reader, error) - CreateBuildLogReader(buildId string) (io.Reader, error) -} + if !w.skipEntryConstructor { + b, err = w.ConstructJsonLogEntry(p) + if err != nil { + return len(p), err + } + } + + _, err = w.logFile.Write(b) + if err != nil { + return len(p), err + } -type loggerFactoryImpl struct { - wsLogsDir string - buildLogsDir string + return len(p), nil } -func NewLoggerFactory(wsLogsDir *string, buildLogsDir *string) LoggerFactory { - loggerFactoryImpl := &loggerFactoryImpl{} +func (w *logger) ConstructJsonLogEntry(p []byte) ([]byte, error) { + var entry LogEntry + entry.Msg = string(p) + entry.Source = string(w.source) + entry.Label = w.label + entry.Time = time.Now().Format(time.RFC3339) - if wsLogsDir != nil { - loggerFactoryImpl.wsLogsDir = *wsLogsDir + b, err := json.Marshal(entry) + if err != nil { + return nil, err } - if buildLogsDir != nil { - loggerFactoryImpl.buildLogsDir = *buildLogsDir + return append(b, []byte(LogDelimiter)...), nil +} + +func (w *logger) Close() error { + if w.logFile != nil { + err := w.logFile.Close() + w.logFile = nil + return err + } + return nil +} + +func (w *logger) Cleanup() error { + workspaceLogsDir := filepath.Join(w.logsDir, w.id) + + _, err := os.Stat(workspaceLogsDir) + if os.IsNotExist(err) { + return nil + } else if err != nil { + return err } - return loggerFactoryImpl + return os.RemoveAll(workspaceLogsDir) } diff --git a/pkg/logs/project.go b/pkg/logs/project.go deleted file mode 100644 index 23d9f50e04..0000000000 --- a/pkg/logs/project.go +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package logs - -import ( - "encoding/json" - "io" - "os" - "path/filepath" - "time" - - "github.com/sirupsen/logrus" -) - -type projectLogger struct { - logsDir string - workspaceId string - projectName string - logFile *os.File - logger *logrus.Logger - source LogSource -} - -func (pl *projectLogger) Write(p []byte) (n int, err error) { - if pl.logFile == nil { - filePath := filepath.Join(pl.logsDir, pl.workspaceId, pl.projectName, "log") - err = os.MkdirAll(filepath.Dir(filePath), 0755) - if err != nil { - return len(p), err - } - - logFile, err := os.OpenFile(filePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) - if err != nil { - return len(p), err - } - pl.logFile = logFile - pl.logger.SetOutput(pl.logFile) - } - - var entry LogEntry - entry.Msg = string(p) - entry.Source = string(pl.source) - entry.WorkspaceId = &pl.workspaceId - entry.ProjectName = &pl.projectName - entry.Time = time.Now().Format(time.RFC3339) - - b, err := json.Marshal(entry) - if err != nil { - return len(p), err - } - - b = append(b, []byte(LogDelimiter)...) - - _, err = pl.logFile.Write(b) - if err != nil { - return len(p), err - } - - return len(p), nil -} - -func (pl *projectLogger) Close() error { - if pl.logFile != nil { - err := pl.logFile.Close() - pl.logFile = nil - return err - } - return nil -} - -func (pl *projectLogger) Cleanup() error { - projectLogsDir := filepath.Join(pl.logsDir, pl.workspaceId, pl.projectName) - - _, err := os.Stat(projectLogsDir) - if os.IsNotExist(err) { - return nil - } else if err != nil { - return err - } - - return os.RemoveAll(projectLogsDir) -} - -func (l *loggerFactoryImpl) CreateProjectLogger(workspaceId, projectName string, source LogSource) Logger { - logger := logrus.New() - - return &projectLogger{ - workspaceId: workspaceId, - logsDir: l.wsLogsDir, - projectName: projectName, - logger: logger, - source: source, - } -} - -func (l *loggerFactoryImpl) CreateProjectLogReader(workspaceId, projectName string) (io.Reader, error) { - filePath := filepath.Join(l.wsLogsDir, workspaceId, projectName, "log") - return os.Open(filePath) -} diff --git a/pkg/logs/remote_factory.go b/pkg/logs/remote_factory.go new file mode 100644 index 0000000000..99420029a9 --- /dev/null +++ b/pkg/logs/remote_factory.go @@ -0,0 +1,61 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package logs + +import ( + "context" + "errors" + "fmt" + "io" + + "github.com/daytonaio/daytona/internal/util" +) + +type remoteLoggerFactory struct { + localLoggerFactory ILoggerFactory + apiUrl string + apiKey string + apiBasePath ApiBasePath +} + +type RemoteLoggerFactoryConfig struct { + LogsDir string + ApiUrl string + ApiKey string + ApiBasePath ApiBasePath +} + +type ApiBasePath string + +var ( + ApiBasePathWorkspace ApiBasePath = "/log/workspace" + ApiBasePathBuild ApiBasePath = "/log/build" + ApiBasePathRunner ApiBasePath = "/log/runner" + ApiBasePathTarget ApiBasePath = "/log/target" +) + +func (r *remoteLoggerFactory) CreateLogger(id, label string, source LogSource) (Logger, error) { + conn, _, err := util.GetWebsocketConn(context.Background(), fmt.Sprintf("%s/%s/write", r.apiBasePath, id), r.apiUrl, r.apiKey, nil) + if err != nil { + return nil, err + } + + localLogger, err := r.localLoggerFactory.CreateLogger(id, label, source) + if err != nil { + return nil, err + } + + return &RemoteLogger{ + localLogger: localLogger, + conn: conn, + }, nil +} + +func (l *remoteLoggerFactory) CreateLogReader(id string) (io.Reader, error) { + return nil, errors.New("not implemented") +} + +func (l *remoteLoggerFactory) CreateLogWriter(id string) (io.WriteCloser, error) { + return nil, errors.New("not implemented") +} diff --git a/pkg/logs/remote_logger.go b/pkg/logs/remote_logger.go new file mode 100644 index 0000000000..faf615bc3a --- /dev/null +++ b/pkg/logs/remote_logger.go @@ -0,0 +1,57 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package logs + +import ( + "github.com/gorilla/websocket" +) + +type RemoteLogger struct { + localLogger Logger + conn *websocket.Conn +} + +func (r *RemoteLogger) Write(p []byte) (n int, err error) { + if r.conn != nil { + b, err := r.localLogger.ConstructJsonLogEntry(p) + if err != nil { + return len(p), err + } + + err = r.conn.WriteMessage(websocket.TextMessage, b) + if err != nil { + return len(p), err + } + } + + return r.localLogger.Write(p) +} + +func (r *RemoteLogger) Cleanup() error { + if r.conn != nil { + err := r.conn.Close() + r.conn = nil + if err != nil { + return err + } + } + + return r.localLogger.Cleanup() +} + +func (r *RemoteLogger) Close() error { + if r.conn != nil { + err := r.conn.Close() + r.conn = nil + if err != nil { + return err + } + } + + return r.localLogger.Close() +} + +func (r *RemoteLogger) ConstructJsonLogEntry(p []byte) ([]byte, error) { + return r.localLogger.ConstructJsonLogEntry(p) +} diff --git a/pkg/logs/types.go b/pkg/logs/types.go new file mode 100644 index 0000000000..380d9340c7 --- /dev/null +++ b/pkg/logs/types.go @@ -0,0 +1,92 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package logs + +import ( + "fmt" + "os" + "strconv" + + log "github.com/sirupsen/logrus" +) + +var defaultLogFileConfig = LogFileConfig{ + MaxSize: 100, // megabytes + MaxBackups: 7, + MaxAge: 15, // days + LocalTime: true, + Compress: true, +} + +type LogFileConfig struct { + Path string `json:"path" validate:"required"` + MaxSize int32 `json:"maxSize" validate:"required"` + MaxBackups int32 `json:"maxBackups" validate:"required"` + MaxAge int32 `json:"maxAge" validate:"required"` + LocalTime bool `json:"localTime" validate:"optional"` + Compress bool `json:"compress" validate:"optional"` +} // @name LogFileConfig + +func GetDefaultLogFileConfig(logFilePath string) *LogFileConfig { + logFileConfig := LogFileConfig{ + Path: logFilePath, + MaxSize: defaultLogFileConfig.MaxSize, + MaxBackups: defaultLogFileConfig.MaxBackups, + MaxAge: defaultLogFileConfig.MaxAge, + LocalTime: defaultLogFileConfig.LocalTime, + Compress: defaultLogFileConfig.Compress, + } + + logFileMaxSize := os.Getenv("DEFAULT_LOG_FILE_MAX_SIZE") + if logFileMaxSize != "" { + value, err := strconv.Atoi(logFileMaxSize) + if err != nil { + log.Error(fmt.Printf("%s. Using default log file max size.", err)) + } else { + logFileConfig.MaxSize = int32(value) + } + } + + logFileMaxBackups := os.Getenv("DEFAULT_LOG_FILE_MAX_BACKUPS") + if logFileMaxBackups != "" { + value, err := strconv.Atoi(logFileMaxBackups) + if err != nil { + log.Error(fmt.Printf("%s. Using default log file max backups.", err)) + } else { + logFileConfig.MaxBackups = int32(value) + } + } + + logFileMaxAge := os.Getenv("DEFAULT_LOG_FILE_MAX_AGE") + if logFileMaxAge != "" { + value, err := strconv.Atoi(logFileMaxAge) + if err != nil { + log.Error(fmt.Printf("%s. Using default log file max age.", err)) + } else { + logFileConfig.MaxAge = int32(value) + } + } + + logFileLocalTime := os.Getenv("DEFAULT_LOG_FILE_LOCAL_TIME") + if logFileLocalTime != "" { + value, err := strconv.ParseBool(logFileLocalTime) + if err != nil { + log.Error(fmt.Printf("%s. Using default log file local time.", err)) + } else { + logFileConfig.LocalTime = value + } + } + + logFileCompress := os.Getenv("DEFAULT_LOG_FILE_COMPRESS") + if logFileCompress != "" { + value, err := strconv.ParseBool(logFileCompress) + if err != nil { + log.Error(fmt.Printf("%s. Using default log file compress.", err)) + } else { + logFileConfig.Compress = value + } + } + + return &logFileConfig +} diff --git a/pkg/logs/workspace.go b/pkg/logs/workspace.go deleted file mode 100644 index 277055bbee..0000000000 --- a/pkg/logs/workspace.go +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package logs - -import ( - "encoding/json" - "io" - "os" - "path/filepath" - "time" - - "github.com/sirupsen/logrus" -) - -type workspaceLogger struct { - logsDir string - workspaceId string - logFile *os.File - logger *logrus.Logger - source LogSource -} - -func (w *workspaceLogger) Write(p []byte) (n int, err error) { - if w.logFile == nil { - filePath := filepath.Join(w.logsDir, w.workspaceId, "log") - err = os.MkdirAll(filepath.Dir(filePath), 0755) - if err != nil { - return len(p), err - } - logFile, err := os.OpenFile(filePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) - if err != nil { - return len(p), err - } - w.logFile = logFile - w.logger.SetOutput(w.logFile) - } - - var entry LogEntry - entry.Msg = string(p) - entry.Source = string(w.source) - entry.WorkspaceId = &w.workspaceId - entry.Time = time.Now().Format(time.RFC3339) - - b, err := json.Marshal(entry) - if err != nil { - return len(p), err - } - - b = append(b, []byte(LogDelimiter)...) - - _, err = w.logFile.Write(b) - if err != nil { - return len(p), err - } - - return len(p), nil -} - -func (w *workspaceLogger) Close() error { - if w.logFile != nil { - err := w.logFile.Close() - w.logFile = nil - return err - } - return nil -} - -func (w *workspaceLogger) Cleanup() error { - workspaceLogsDir := filepath.Join(w.logsDir, w.workspaceId) - - _, err := os.Stat(workspaceLogsDir) - if os.IsNotExist(err) { - return nil - } else if err != nil { - return err - } - - return os.RemoveAll(workspaceLogsDir) -} - -func (l *loggerFactoryImpl) CreateWorkspaceLogger(workspaceId string, source LogSource) Logger { - logger := logrus.New() - - return &workspaceLogger{ - workspaceId: workspaceId, - logsDir: l.wsLogsDir, - logger: logger, - source: source, - } -} - -func (l *loggerFactoryImpl) CreateWorkspaceLogReader(workspaceId string) (io.Reader, error) { - filePath := filepath.Join(l.wsLogsDir, workspaceId, "log") - return os.Open(filePath) -} diff --git a/pkg/models/api_key.go b/pkg/models/api_key.go new file mode 100644 index 0000000000..b162772bf8 --- /dev/null +++ b/pkg/models/api_key.go @@ -0,0 +1,20 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package models + +type ApiKeyType string + +const ( + ApiKeyTypeClient ApiKeyType = "client" + ApiKeyTypeWorkspace ApiKeyType = "workspace" + ApiKeyTypeTarget ApiKeyType = "target" + ApiKeyTypeRunner ApiKeyType = "runner" +) + +type ApiKey struct { + KeyHash string `json:"keyHash" validate:"required" gorm:"primaryKey"` + Type ApiKeyType `json:"type" validate:"required" gorm:"not null" ` + // Workspace or client name + Name string `json:"name" validate:"required" gorm:"uniqueIndex;not null"` +} // @name ApiKey diff --git a/pkg/build/build.go b/pkg/models/build.go similarity index 57% rename from pkg/build/build.go rename to pkg/models/build.go index a21d34a2d0..d373f43f50 100644 --- a/pkg/build/build.go +++ b/pkg/models/build.go @@ -1,6 +1,6 @@ // Copyright 2024 Daytona Platforms Inc. // SPDX-License-Identifier: Apache-2.0 -package build +package models import ( "crypto/sha256" @@ -9,39 +9,34 @@ import ( "time" "github.com/daytonaio/daytona/pkg/gitprovider" - "github.com/daytonaio/daytona/pkg/workspace/project/buildconfig" - "github.com/daytonaio/daytona/pkg/workspace/project/containerconfig" -) - -type BuildState string - -const ( - BuildStatePendingRun BuildState = "pending-run" - BuildStateRunning BuildState = "running" - BuildStateError BuildState = "error" - BuildStateSuccess BuildState = "success" - BuildStatePublished BuildState = "published" - BuildStatePendingDelete BuildState = "pending-delete" - BuildStatePendingForcedDelete BuildState = "pending-forced-delete" - BuildStateDeleting BuildState = "deleting" ) type Build struct { - Id string `json:"id" validate:"required"` - State BuildState `json:"state" validate:"required"` - Image *string `json:"image" validate:"optional"` - User *string `json:"user" validate:"optional"` - ContainerConfig containerconfig.ContainerConfig `json:"containerConfig" validate:"required"` - BuildConfig *buildconfig.BuildConfig `json:"buildConfig" validate:"optional"` - Repository *gitprovider.GitRepository `json:"repository" validate:"required"` - EnvVars map[string]string `json:"envVars" validate:"required"` - PrebuildId string `json:"prebuildId" validate:"required"` - CreatedAt time.Time `json:"createdAt" validate:"required"` - UpdatedAt time.Time `json:"updatedAt" validate:"required"` + Id string `json:"id" validate:"required" gorm:"primaryKey"` + Image *string `json:"image" validate:"optional"` + User *string `json:"user" validate:"optional"` + ContainerConfig ContainerConfig `json:"containerConfig" validate:"required" gorm:"serializer:json;not null"` + BuildConfig *BuildConfig `json:"buildConfig" validate:"optional" gorm:"serializer:json"` + Repository *gitprovider.GitRepository `json:"repository" validate:"required" gorm:"serializer:json;not null"` + EnvVars map[string]string `json:"envVars" validate:"required" gorm:"serializer:json;not null"` + LastJobId *string `json:"lastJobId" validate:"optional"` + LastJob *Job `json:"lastJob" validate:"optional" gorm:"foreignKey:LastJobId;references:Id"` + PrebuildId *string `json:"prebuildId" validate:"optional"` + CreatedAt time.Time `json:"createdAt" validate:"required" gorm:"not null"` + UpdatedAt time.Time `json:"updatedAt" validate:"required" gorm:"not null"` } // @name Build +func (w *Build) GetState() ResourceState { + return getResourceStateFromJob(w.LastJob) +} + +type ContainerConfig struct { + Image string `json:"image" validate:"required" gorm:"not null"` + User string `json:"user" validate:"required" gorm:"not null"` +} // @name ContainerConfig + func (b *Build) Compare(other *Build) (bool, error) { - if b.BuildConfig != nil && *b.BuildConfig == (buildconfig.BuildConfig{}) { + if b.BuildConfig != nil && *b.BuildConfig == (BuildConfig{}) { buildHash, err := b.getBuildHashWithoutBuildConfig() if err != nil { return false, err @@ -103,7 +98,7 @@ func (b *Build) getBuildHashWithoutBuildConfig() (string, error) { return hashStr, nil } -func GetCachedBuild(build *Build, builds []*Build) *buildconfig.CachedBuild { +func GetCachedBuild(build *Build, builds []*Build) *CachedBuild { var cachedBuild *Build for _, existingBuild := range builds { @@ -111,7 +106,7 @@ func GetCachedBuild(build *Build, builds []*Build) *buildconfig.CachedBuild { if err != nil { continue } - if !equal || existingBuild.State != BuildStatePublished { + if !equal || existingBuild.GetState().Name != ResourceStateNameRunSuccessful { continue } if cachedBuild == nil { @@ -124,7 +119,7 @@ func GetCachedBuild(build *Build, builds []*Build) *buildconfig.CachedBuild { } if cachedBuild != nil && cachedBuild.Image != nil && cachedBuild.User != nil { - return &buildconfig.CachedBuild{ + return &CachedBuild{ Image: *cachedBuild.Image, User: *cachedBuild.User, } diff --git a/pkg/models/common.go b/pkg/models/common.go new file mode 100644 index 0000000000..4a6ee240aa --- /dev/null +++ b/pkg/models/common.go @@ -0,0 +1,45 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package models + +import "time" + +type ResourceState struct { + Name ResourceStateName `json:"name" validate:"required"` + Error *string `json:"error" validate:"optional"` + UpdatedAt time.Time `json:"updatedAt" validate:"required"` +} // @name ResourceState + +type ResourceStateName string + +const ( + ResourceStateNameUndefined ResourceStateName = "undefined" + ResourceStateNamePendingRun ResourceStateName = "pending-run" + ResourceStateNameRunning ResourceStateName = "running" + ResourceStateNameRunSuccessful ResourceStateName = "run-successful" + ResourceStateNamePendingCreate ResourceStateName = "pending-create" + ResourceStateNameCreating ResourceStateName = "creating" + ResourceStateNamePendingStart ResourceStateName = "pending-start" + ResourceStateNameStarting ResourceStateName = "starting" + ResourceStateNameStarted ResourceStateName = "started" + ResourceStateNamePendingStop ResourceStateName = "pending-stop" + ResourceStateNameStopping ResourceStateName = "stopping" + ResourceStateNameStopped ResourceStateName = "stopped" + ResourceStateNamePendingRestart ResourceStateName = "pending-restart" + ResourceStateNameError ResourceStateName = "error" + ResourceStateNameUnresponsive ResourceStateName = "unresponsive" + ResourceStateNamePendingDelete ResourceStateName = "pending-delete" + ResourceStateNamePendingForcedDelete ResourceStateName = "pending-forced-delete" + ResourceStateNameDeleting ResourceStateName = "deleting" + ResourceStateNameDeleted ResourceStateName = "deleted" +) + +type BuildConfig struct { + Devcontainer *DevcontainerConfig `json:"devcontainer,omitempty" validate:"optional"` + CachedBuild *CachedBuild `json:"cachedBuild,omitempty" validate:"optional"` +} // @name BuildConfig + +type DevcontainerConfig struct { + FilePath string `json:"filePath" validate:"required"` +} // @name DevcontainerConfig diff --git a/pkg/models/container_registry.go b/pkg/models/container_registry.go new file mode 100644 index 0000000000..c7de259fc6 --- /dev/null +++ b/pkg/models/container_registry.go @@ -0,0 +1,11 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package models + +// ContainerRegistry represents a container registry credentials +type ContainerRegistry struct { + Server string `json:"server" validate:"required" gorm:"primaryKey"` + Username string `json:"username" validate:"required"` + Password string `json:"password" validate:"required"` +} // @name ContainerRegistry diff --git a/pkg/models/env.go b/pkg/models/env.go new file mode 100644 index 0000000000..5772ed160e --- /dev/null +++ b/pkg/models/env.go @@ -0,0 +1,9 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package models + +type EnvironmentVariable struct { + Key string `json:"key" validate:"required" gorm:"primaryKey"` + Value string `json:"value" validate:"required" gorm:"not null"` +} // @name EnvironmentVariable diff --git a/pkg/models/git_provider_config.go b/pkg/models/git_provider_config.go new file mode 100644 index 0000000000..c012518dd7 --- /dev/null +++ b/pkg/models/git_provider_config.go @@ -0,0 +1,22 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package models + +type SigningMethod string // @name SigningMethod + +const ( + SigningMethodSSH SigningMethod = "ssh" + SigningMethodGPG SigningMethod = "gpg" +) + +type GitProviderConfig struct { + Id string `json:"id" validate:"required" gorm:"primaryKey"` + ProviderId string `json:"providerId" validate:"required" gorm:"not null"` + Username string `json:"username" validate:"required" gorm:"not null"` + BaseApiUrl *string `json:"baseApiUrl,omitempty" validate:"optional"` + Token string `json:"token" validate:"required" gorm:"not null"` + Alias string `json:"alias" validate:"required" gorm:"uniqueIndex;not null"` + SigningKey *string `json:"signingKey,omitempty" validate:"optional"` + SigningMethod *SigningMethod `json:"signingMethod,omitempty" validate:"optional"` +} // @name GitProvider diff --git a/pkg/models/job.go b/pkg/models/job.go new file mode 100644 index 0000000000..84abd3550b --- /dev/null +++ b/pkg/models/job.go @@ -0,0 +1,108 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package models + +import ( + "time" +) + +type Job struct { + Id string `json:"id" validate:"required" gorm:"primaryKey"` + ResourceId string `json:"resourceId" validate:"required" gorm:"not null"` + RunnerId *string `json:"runnerId" validate:"optional"` + ResourceType ResourceType `json:"resourceType" validate:"required" gorm:"not null"` + State JobState `json:"state" validate:"required" gorm:"not null"` + Action JobAction `json:"action" validate:"required" gorm:"not null"` + // JSON encoded metadata + Metadata *string `json:"metadata" validate:"optional"` + Error *string `json:"error" validate:"optional"` + CreatedAt time.Time `json:"createdAt" validate:"required" gorm:"not null"` + UpdatedAt time.Time `json:"updatedAt" validate:"required" gorm:"not null"` +} // @name Job + +type ResourceType string // @name ResourceType + +const ( + ResourceTypeWorkspace ResourceType = "workspace" + ResourceTypeTarget ResourceType = "target" + ResourceTypeBuild ResourceType = "build" + ResourceTypeRunner ResourceType = "runner" +) + +type JobState string // @name JobState + +const ( + JobStatePending JobState = "pending" + JobStateRunning JobState = "running" + JobStateError JobState = "error" + JobStateSuccess JobState = "success" +) + +type JobAction string + +const ( + JobActionCreate JobAction = "create" + JobActionStart JobAction = "start" + JobActionStop JobAction = "stop" + JobActionRestart JobAction = "restart" + JobActionDelete JobAction = "delete" + JobActionForceDelete JobAction = "force-delete" + JobActionRun JobAction = "run" + JobActionInstallProvider JobAction = "install-provider" + JobActionUninstallProvider JobAction = "uninstall-provider" + JobActionUpdateProvider JobAction = "update-provider" +) + +func getResourceStateFromJob(job *Job) ResourceState { + state := ResourceState{ + Name: ResourceStateNameUnresponsive, + UpdatedAt: time.Now(), + } + + if job == nil { + return state + } + + if job.State == JobStateSuccess { + switch job.Action { + case JobActionRun: + state.Name = ResourceStateNameRunSuccessful + case JobActionCreate: + state.Name = ResourceStateNameStarted + case JobActionStart: + state.Name = ResourceStateNameStarted + case JobActionStop: + state.Name = ResourceStateNameStopped + case JobActionRestart: + state.Name = ResourceStateNameStarted + case JobActionDelete: + state.Name = ResourceStateNameDeleted + case JobActionForceDelete: + state.Name = ResourceStateNameDeleted + } + } else if job.State == JobStateError { + state.Name = ResourceStateNameError + state.Error = job.Error + } else if job.State == JobStateRunning { + switch job.Action { + case JobActionRun: + state.Name = ResourceStateNameRunning + case JobActionCreate: + state.Name = ResourceStateNameCreating + case JobActionStart: + state.Name = ResourceStateNameStarting + case JobActionStop: + state.Name = ResourceStateNameStopping + case JobActionRestart: + state.Name = ResourceStateNameStarting + case JobActionDelete: + state.Name = ResourceStateNameDeleting + case JobActionForceDelete: + state.Name = ResourceStateNameDeleting + } + } + + state.UpdatedAt = job.UpdatedAt + return state +} diff --git a/pkg/models/provider_info.go b/pkg/models/provider_info.go new file mode 100644 index 0000000000..78ad3cf390 --- /dev/null +++ b/pkg/models/provider_info.go @@ -0,0 +1,45 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package models + +type ProviderInfo struct { + RunnerId string `json:"runnerId" validate:"required"` + RunnerName string `json:"runnerName" validate:"required"` + Name string `json:"name" validate:"required"` + Version string `json:"version" validate:"required"` + AgentlessTarget bool `json:"agentlessTarget" validate:"optional"` + Label *string `json:"label" validate:"optional"` + TargetConfigManifest TargetConfigManifest `json:"targetConfigManifest" validate:"required"` +} // @name ProviderInfo + +type TargetConfigManifest map[string]TargetConfigProperty // @name TargetConfigManifest + +type TargetConfigPropertyType string + +const ( + TargetConfigPropertyTypeString TargetConfigPropertyType = "string" + TargetConfigPropertyTypeOption TargetConfigPropertyType = "option" + TargetConfigPropertyTypeBoolean TargetConfigPropertyType = "boolean" + TargetConfigPropertyTypeInt TargetConfigPropertyType = "int" + TargetConfigPropertyTypeFloat TargetConfigPropertyType = "float" + TargetConfigPropertyTypeFilePath TargetConfigPropertyType = "file-path" +) + +type TargetConfigProperty struct { + Type TargetConfigPropertyType + InputMasked bool + // A regex string matched with the name of the target config to determine if the property should be disabled + // If the regex matches the target config name, the property will be disabled + // E.g. "^local$" will disable the property for the local target + DisabledPredicate string + // DefaultValue is converted into the appropriate type based on the Type + // If the property is a FilePath, the DefaultValue is a path to a directory + DefaultValue string + // Brief description of the property + Description string + // Options is only used if the Type is TargetConfigPropertyTypeOption + Options []string + // Suggestions is an optional list of auto-complete values to assist the user while filling the field + Suggestions []string +} // @name TargetConfigProperty diff --git a/pkg/models/runner.go b/pkg/models/runner.go new file mode 100644 index 0000000000..cb605327bb --- /dev/null +++ b/pkg/models/runner.go @@ -0,0 +1,44 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package models + +import ( + "time" + + "github.com/daytonaio/daytona/internal/util" +) + +type Runner struct { + Id string `json:"id" validate:"required" gorm:"primaryKey"` + Name string `json:"name" validate:"required" gorm:"uniqueIndex;not null"` + ApiKey string `json:"-" validate:"required" gorm:"not null"` + Metadata *RunnerMetadata `json:"metadata" validate:"optional" gorm:"foreignKey:Id;references:RunnerId"` +} // @name Runner + +func (r *Runner) GetState() ResourceState { + var state ResourceState + state.Name = ResourceStateNameUnresponsive + state.UpdatedAt = time.Now() + state.Error = util.Pointer("Runner is unresponsive") + + if r.Metadata == nil { + return state + } + + if r.Metadata != nil && (time.Since(r.Metadata.UpdatedAt) > RESOURCE_UNRESPONSIVE_THRESHOLD || r.Metadata.Uptime == 0) { + state.UpdatedAt = r.Metadata.UpdatedAt + return state + } + + state.Name = ResourceStateNameStarted + return state +} + +type RunnerMetadata struct { + RunnerId string `json:"runnerId" validate:"required" gorm:"primaryKey"` + UpdatedAt time.Time `json:"updatedAt" validate:"required" gorm:"not null"` + Uptime uint64 `json:"uptime" validate:"required" gorm:"not null"` + RunningJobs *uint64 `json:"runningJobs,omitempty" validate:"optional" gorm:"default:0"` + Providers []ProviderInfo `json:"providers" validate:"required" gorm:"serializer:json;not null"` +} // @name RunnerMetadata diff --git a/pkg/models/target.go b/pkg/models/target.go new file mode 100644 index 0000000000..df50e6e2fd --- /dev/null +++ b/pkg/models/target.go @@ -0,0 +1,67 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package models + +import ( + "time" + + "github.com/daytonaio/daytona/internal/util" +) + +const RESOURCE_UNRESPONSIVE_THRESHOLD = 30 * time.Second + +type Target struct { + Id string `json:"id" validate:"required" gorm:"primaryKey"` + Name string `json:"name" validate:"required" gorm:"not null"` + TargetConfigId string `json:"targetConfigId" validate:"required" gorm:"not null"` + TargetConfig TargetConfig `json:"targetConfig" validate:"required" gorm:"foreignKey:TargetConfigId"` + ApiKey string `json:"-" validate:"required" gorm:"not null"` + EnvVars map[string]string `json:"envVars" validate:"required" gorm:"serializer:json;not null"` + IsDefault bool `json:"default" validate:"required" gorm:"not null"` + Workspaces []Workspace `json:"workspaces" validate:"required"` + Metadata *TargetMetadata `json:"metadata" validate:"optional" gorm:"foreignKey:Id;references:TargetId"` + LastJobId *string `json:"lastJobId" validate:"optional"` + LastJob *Job `json:"lastJob" validate:"optional" gorm:"foreignKey:LastJobId;references:Id"` + ProviderMetadata *string `json:"providerMetadata,omitempty" validate:"optional"` +} // @name Target + +type TargetMetadata struct { + TargetId string `json:"targetId" validate:"required" gorm:"primaryKey"` + UpdatedAt time.Time `json:"updatedAt" validate:"required" gorm:"not null"` + Uptime uint64 `json:"uptime" validate:"required" gorm:"not null"` +} // @name TargetMetadata + +var allowedAgentlessTargetStates = map[ResourceStateName]bool{ + ResourceStateNamePendingCreate: true, + ResourceStateNameCreating: true, + ResourceStateNameError: true, + ResourceStateNameDeleted: true, +} + +func (t *Target) GetState() ResourceState { + state := getResourceStateFromJob(t.LastJob) + + // Some providers do not utilize agents in target mode + if t.TargetConfig.ProviderInfo.AgentlessTarget { + if allowedAgentlessTargetStates[state.Name] { + return state + } + + return ResourceState{ + Name: ResourceStateNameUndefined, + UpdatedAt: time.Now(), + } + } + + // If the target should be running, check if it is unresponsive + if state.Name == ResourceStateNameStarted { + if t.Metadata != nil && time.Since(t.Metadata.UpdatedAt) > RESOURCE_UNRESPONSIVE_THRESHOLD { + state.Name = ResourceStateNameUnresponsive + state.Error = util.Pointer("Target is unresponsive") + state.UpdatedAt = t.Metadata.UpdatedAt + } + } + + return state +} diff --git a/pkg/models/target_config.go b/pkg/models/target_config.go new file mode 100644 index 0000000000..6e2ffb4d74 --- /dev/null +++ b/pkg/models/target_config.go @@ -0,0 +1,13 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package models + +type TargetConfig struct { + Id string `json:"id" validate:"required" gorm:"primaryKey"` + Name string `json:"name" validate:"required" gorm:"not null"` + ProviderInfo ProviderInfo `json:"providerInfo" validate:"required" gorm:"serializer:json;not null"` + // JSON encoded map of options + Options string `json:"options" validate:"required" gorm:"not null"` + Deleted bool `json:"deleted" validate:"required" gorm:"not null"` +} // @name TargetConfig diff --git a/pkg/models/workspace.go b/pkg/models/workspace.go new file mode 100644 index 0000000000..c60fa98f07 --- /dev/null +++ b/pkg/models/workspace.go @@ -0,0 +1,93 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package models + +import ( + "time" + + "github.com/daytonaio/daytona/internal/util" + "github.com/daytonaio/daytona/pkg/gitprovider" +) + +type Workspace struct { + Id string `json:"id" validate:"required" gorm:"primaryKey"` + Name string `json:"name" validate:"required" gorm:"not null"` + Image string `json:"image" validate:"required" gorm:"not null"` + User string `json:"user" validate:"required" gorm:"not null"` + BuildConfig *BuildConfig `json:"buildConfig,omitempty" validate:"optional" gorm:"serializer:json"` + Repository *gitprovider.GitRepository `json:"repository" validate:"required" gorm:"serializer:json;not null"` + EnvVars map[string]string `json:"envVars" validate:"required" gorm:"serializer:json;not null"` + Labels map[string]string `json:"labels" validate:"required" gorm:"serializer:json;not null"` + TargetId string `json:"targetId" validate:"required" gorm:"not null"` + Target Target `json:"target" validate:"required" gorm:"foreignKey:TargetId"` + ApiKey string `json:"apiKey" validate:"required" gorm:"not null"` + Metadata *WorkspaceMetadata `json:"metadata" validate:"optional" gorm:"foreignKey:Id;references:WorkspaceId"` + GitProviderConfigId *string `json:"gitProviderConfigId,omitempty" validate:"optional"` + LastJobId *string `json:"lastJobId" validate:"optional"` + LastJob *Job `json:"lastJob" validate:"optional" gorm:"foreignKey:LastJobId;references:Id"` + ProviderMetadata *string `json:"providerMetadata,omitempty" validate:"optional"` +} // @name Workspace + +type WorkspaceMetadata struct { + WorkspaceId string `json:"workspaceId" validate:"required" gorm:"primaryKey"` + UpdatedAt time.Time `json:"updatedAt" validate:"required" gorm:"not null"` + Uptime uint64 `json:"uptime" validate:"required" gorm:"not null"` + GitStatus *GitStatus `json:"gitStatus" validate:"optional" gorm:"serializer:json"` +} // @name WorkspaceMetadata + +func (w *Workspace) WorkspaceFolderName() string { + if w.Repository != nil { + return w.Repository.Name + } + return w.Name +} + +func (w *Workspace) GetState() ResourceState { + state := getResourceStateFromJob(w.LastJob) + + // If the workspace should be running, check if it is unresponsive + if state.Name == ResourceStateNameStarted { + if w.Metadata != nil && time.Since(w.Metadata.UpdatedAt) > RESOURCE_UNRESPONSIVE_THRESHOLD { + state.Name = ResourceStateNameUnresponsive + state.Error = util.Pointer("Workspace is unresponsive") + state.UpdatedAt = w.Metadata.UpdatedAt + } + } + + return state +} + +type CachedBuild struct { + User string `json:"user" validate:"required"` + Image string `json:"image" validate:"required"` +} // @name CachedBuild + +type GitStatus struct { + CurrentBranch string `json:"currentBranch" validate:"required"` + Files []*FileStatus `json:"fileStatus" validate:"required"` + BranchPublished bool `json:"branchPublished" validate:"optional"` + Ahead int `json:"ahead" validate:"optional"` + Behind int `json:"behind" validate:"optional"` +} // @name GitStatus + +type FileStatus struct { + Name string `json:"name" validate:"required"` + Extra string `json:"extra" validate:"required"` + Staging Status `json:"staging" validate:"required"` + Worktree Status `json:"worktree" validate:"required"` +} // @name FileStatus + +// Status status code of a file in the Worktree +type Status string // @name Status + +const ( + Unmodified Status = "Unmodified" + Untracked Status = "Untracked" + Modified Status = "Modified" + Added Status = "Added" + Deleted Status = "Deleted" + Renamed Status = "Renamed" + Copied Status = "Copied" + UpdatedButUnmerged Status = "Updated but unmerged" +) diff --git a/pkg/models/workspace_template.go b/pkg/models/workspace_template.go new file mode 100644 index 0000000000..015ae0148d --- /dev/null +++ b/pkg/models/workspace_template.go @@ -0,0 +1,142 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package models + +import ( + "encoding/json" + "errors" + "sort" + + "github.com/docker/docker/pkg/stringid" +) + +type WorkspaceTemplate struct { + Name string `json:"name" validate:"required" gorm:"primaryKey"` + Image string `json:"image" validate:"required" gorm:"not null"` + User string `json:"user" validate:"required" gorm:"not null"` + BuildConfig *BuildConfig `json:"buildConfig,omitempty" validate:"optional" gorm:"serializer:json"` + RepositoryUrl string `json:"repositoryUrl" validate:"required" gorm:"not null"` + EnvVars map[string]string `json:"envVars" validate:"required" gorm:"serializer:json;not null"` + Labels map[string]string `json:"labels" validate:"required" gorm:"serializer:json;not null"` + IsDefault bool `json:"default" validate:"required" gorm:"not null"` + Prebuilds []*PrebuildConfig `json:"prebuilds" validate:"optional" gorm:"serializer:json"` + GitProviderConfigId *string `json:"gitProviderConfigId" validate:"optional"` +} // @name WorkspaceTemplate + +func (wt *WorkspaceTemplate) SetPrebuild(p *PrebuildConfig) error { + newPrebuild := PrebuildConfig{ + Id: p.Id, + Branch: p.Branch, + CommitInterval: p.CommitInterval, + TriggerFiles: p.TriggerFiles, + Retention: p.Retention, + } + + for _, pb := range wt.Prebuilds { + if pb.Id == p.Id { + *pb = newPrebuild + return nil + } + } + + wt.Prebuilds = append(wt.Prebuilds, &newPrebuild) + return nil +} + +func (wt *WorkspaceTemplate) FindPrebuild(filter *MatchParams) (*PrebuildConfig, error) { + for _, pb := range wt.Prebuilds { + if pb.Match(filter) { + return pb, nil + } + } + + return nil, errors.New("prebuild not found") +} + +func (wt *WorkspaceTemplate) ListPrebuilds(filter *MatchParams) ([]*PrebuildConfig, error) { + if filter == nil { + return wt.Prebuilds, nil + } + + prebuilds := []*PrebuildConfig{} + + for _, pb := range wt.Prebuilds { + if pb.Match(filter) { + prebuilds = append(prebuilds, pb) + } + } + + return prebuilds, nil +} + +func (wt *WorkspaceTemplate) DeletePrebuild(id string) error { + newPrebuilds := []*PrebuildConfig{} + + for _, pb := range wt.Prebuilds { + if pb.Id != id { + newPrebuilds = append(newPrebuilds, pb) + } + } + + wt.Prebuilds = newPrebuilds + return nil +} + +// PrebuildConfig holds configuration for the prebuild process +type PrebuildConfig struct { + Id string `json:"id" validate:"required" gorm:"not null"` + Branch string `json:"branch" validate:"required" gorm:"not null"` + CommitInterval *int `json:"commitInterval" validate:"optional"` + TriggerFiles []string `json:"triggerFiles" validate:"required" gorm:"not null"` + Retention int `json:"retention" validate:"required" gorm:"not null"` +} // @name PrebuildConfig + +func (p *PrebuildConfig) GenerateId() error { + id := stringid.GenerateRandomID() + id = stringid.TruncateID(id) + + p.Id = id + return nil +} + +type MatchParams struct { + WorkspaceTemplateName *string + Id *string + Branch *string + CommitInterval *int + TriggerFiles *[]string +} + +func (p *PrebuildConfig) Match(params *MatchParams) bool { + if params.Id != nil && *params.Id != p.Id { + return false + } + + if params.Branch != nil && *params.Branch != p.Branch { + return false + } + + if params.CommitInterval != nil && p.CommitInterval != nil && *params.CommitInterval != *p.CommitInterval { + return false + } + + if params.TriggerFiles != nil { + // Sort the trigger files before checking if same + sort.Strings(p.TriggerFiles) + sort.Strings(*params.TriggerFiles) + triggerFilesJson, err := json.Marshal(p.TriggerFiles) + if err != nil { + return false + } + filterFilesJson, err := json.Marshal(*params.TriggerFiles) + if err != nil { + return false + } + if string(triggerFilesJson) != string(filterFilesJson) { + return false + } + } + + return true +} diff --git a/pkg/posthogservice/service.go b/pkg/posthogservice/service.go index 26fd119de1..d565705724 100644 --- a/pkg/posthogservice/service.go +++ b/pkg/posthogservice/service.go @@ -4,7 +4,6 @@ package posthogservice import ( - "fmt" "log" "github.com/daytonaio/daytona/pkg/telemetry" @@ -16,6 +15,7 @@ type PosthogServiceConfig struct { ApiKey string Endpoint string Version string + Source telemetry.TelemetrySource } func NewTelemetryService(config PosthogServiceConfig) telemetry.TelemetryService { @@ -25,48 +25,31 @@ func NewTelemetryService(config PosthogServiceConfig) telemetry.TelemetryService Verbose: true, }) posthogService := &posthogService{ - client: client, - AbstractTelemetryService: telemetry.NewAbstractTelemetryService(config.Version), + client: client, + version: config.Version, + source: config.Source, } - posthogService.AbstractTelemetryService.TelemetryService = posthogService - return posthogService } type posthogService struct { - *telemetry.AbstractTelemetryService - - client posthog.Client + client posthog.Client + version string + source telemetry.TelemetrySource } func (p *posthogService) Close() error { return p.client.Close() } -func (p *posthogService) TrackCliEvent(event telemetry.CliEvent, clientId string, properties map[string]interface{}) error { - p.AbstractTelemetryService.SetCommonProps(properties) - return p.client.Enqueue(posthog.Capture{ - DistinctId: clientId, - Event: string(event), - Properties: properties, - }) -} +func (p *posthogService) Track(event telemetry.Event, clientId string) error { + props := event.Props() -func (p *posthogService) TrackServerEvent(event telemetry.ServerEvent, clientId string, properties map[string]interface{}) error { - p.AbstractTelemetryService.SetCommonProps(properties) + telemetry.SetCommonProps(p.version, p.source, props) return p.client.Enqueue(posthog.Capture{ DistinctId: clientId, - Event: string(event), - Properties: properties, - }) -} - -func (p *posthogService) TrackBuildRunnerEvent(event telemetry.BuildRunnerEvent, buildRunnerId string, properties map[string]interface{}) error { - p.AbstractTelemetryService.SetCommonProps(properties) - return p.client.Enqueue(posthog.Capture{ - DistinctId: fmt.Sprintf("build-runner-%s", buildRunnerId), - Event: string(event), - Properties: properties, + Event: event.Name(), + Properties: props, }) } diff --git a/pkg/profiledata/profile_data.go b/pkg/profiledata/profile_data.go deleted file mode 100644 index 29217a8758..0000000000 --- a/pkg/profiledata/profile_data.go +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package profiledata - -type ProfileData struct { - EnvVars map[string]string `json:"envVars" validate:"required"` -} // @name ProfileData diff --git a/pkg/profiledata/store.go b/pkg/profiledata/store.go deleted file mode 100644 index 985c9d1997..0000000000 --- a/pkg/profiledata/store.go +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package profiledata - -import "errors" - -type Store interface { - Get() (*ProfileData, error) - Save(profileData *ProfileData) error - Delete() error -} - -var ( - ErrProfileDataNotFound = errors.New("profile data not found") -) - -func IsProfileDataNotFound(err error) bool { - return err.Error() == ErrProfileDataNotFound.Error() -} diff --git a/pkg/provider/provider.go b/pkg/provider/provider.go index a3fcfcd696..8c7cfaaf5f 100644 --- a/pkg/provider/provider.go +++ b/pkg/provider/provider.go @@ -6,31 +6,29 @@ package provider import ( "net/rpc" + "github.com/daytonaio/daytona/pkg/models" "github.com/daytonaio/daytona/pkg/provider/util" - "github.com/daytonaio/daytona/pkg/workspace" - "github.com/daytonaio/daytona/pkg/workspace/project" "github.com/hashicorp/go-plugin" ) type Provider interface { Initialize(InitializeProviderRequest) (*util.Empty, error) - GetInfo() (ProviderInfo, error) + GetInfo() (models.ProviderInfo, error) CheckRequirements() (*[]RequirementStatus, error) - GetTargetManifest() (*ProviderTargetManifest, error) - GetPresetTargets() (*[]ProviderTarget, error) + GetPresetTargetConfigs() (*[]TargetConfig, error) + + CreateTarget(*TargetRequest) (*util.Empty, error) + StartTarget(*TargetRequest) (*util.Empty, error) + StopTarget(*TargetRequest) (*util.Empty, error) + DestroyTarget(*TargetRequest) (*util.Empty, error) + GetTargetProviderMetadata(*TargetRequest) (string, error) CreateWorkspace(*WorkspaceRequest) (*util.Empty, error) StartWorkspace(*WorkspaceRequest) (*util.Empty, error) StopWorkspace(*WorkspaceRequest) (*util.Empty, error) DestroyWorkspace(*WorkspaceRequest) (*util.Empty, error) - GetWorkspaceInfo(*WorkspaceRequest) (*workspace.WorkspaceInfo, error) - - CreateProject(*ProjectRequest) (*util.Empty, error) - StartProject(*ProjectRequest) (*util.Empty, error) - StopProject(*ProjectRequest) (*util.Empty, error) - DestroyProject(*ProjectRequest) (*util.Empty, error) - GetProjectInfo(*ProjectRequest) (*project.ProjectInfo, error) + GetWorkspaceProviderMetadata(*WorkspaceRequest) (string, error) } type ProviderPlugin struct { diff --git a/pkg/provider/rpc_client.go b/pkg/provider/rpc_client.go index 86f3e8650d..604e1bddd4 100644 --- a/pkg/provider/rpc_client.go +++ b/pkg/provider/rpc_client.go @@ -6,9 +6,8 @@ package provider import ( "net/rpc" + "github.com/daytonaio/daytona/pkg/models" "github.com/daytonaio/daytona/pkg/provider/util" - "github.com/daytonaio/daytona/pkg/workspace" - "github.com/daytonaio/daytona/pkg/workspace/project" ) type ProviderRPCClient struct { @@ -20,8 +19,8 @@ func (m *ProviderRPCClient) Initialize(req InitializeProviderRequest) (*util.Emp return new(util.Empty), err } -func (m *ProviderRPCClient) GetInfo() (ProviderInfo, error) { - var resp ProviderInfo +func (m *ProviderRPCClient) GetInfo() (models.ProviderInfo, error) { + var resp models.ProviderInfo err := m.client.Call("Plugin.GetInfo", new(interface{}), &resp) return resp, err } @@ -32,67 +31,60 @@ func (m *ProviderRPCClient) CheckRequirements() (*[]RequirementStatus, error) { return &result, err } -func (m *ProviderRPCClient) GetTargetManifest() (*ProviderTargetManifest, error) { - var resp ProviderTargetManifest - err := m.client.Call("Plugin.GetTargetManifest", new(interface{}), &resp) - - return &resp, err -} - -func (m *ProviderRPCClient) GetPresetTargets() (*[]ProviderTarget, error) { - var resp []ProviderTarget - err := m.client.Call("Plugin.GetPresetTargets", new(interface{}), &resp) +func (m *ProviderRPCClient) GetPresetTargetConfigs() (*[]TargetConfig, error) { + var resp []TargetConfig + err := m.client.Call("Plugin.GetPresetTargetConfigs", new(interface{}), &resp) return &resp, err } -func (m *ProviderRPCClient) CreateWorkspace(workspaceReq *WorkspaceRequest) (*util.Empty, error) { - err := m.client.Call("Plugin.CreateWorkspace", workspaceReq, new(util.Empty)) +func (m *ProviderRPCClient) CreateTarget(targetReq *TargetRequest) (*util.Empty, error) { + err := m.client.Call("Plugin.CreateTarget", targetReq, new(util.Empty)) return new(util.Empty), err } -func (m *ProviderRPCClient) StartWorkspace(workspaceReq *WorkspaceRequest) (*util.Empty, error) { - err := m.client.Call("Plugin.StartWorkspace", workspaceReq, new(util.Empty)) +func (m *ProviderRPCClient) StartTarget(targetReq *TargetRequest) (*util.Empty, error) { + err := m.client.Call("Plugin.StartTarget", targetReq, new(util.Empty)) return new(util.Empty), err } -func (m *ProviderRPCClient) StopWorkspace(workspaceReq *WorkspaceRequest) (*util.Empty, error) { - err := m.client.Call("Plugin.StopWorkspace", workspaceReq, new(util.Empty)) +func (m *ProviderRPCClient) StopTarget(targetReq *TargetRequest) (*util.Empty, error) { + err := m.client.Call("Plugin.StopTarget", targetReq, new(util.Empty)) return new(util.Empty), err } -func (m *ProviderRPCClient) DestroyWorkspace(workspaceReq *WorkspaceRequest) (*util.Empty, error) { - err := m.client.Call("Plugin.DestroyWorkspace", workspaceReq, new(util.Empty)) +func (m *ProviderRPCClient) DestroyTarget(targetReq *TargetRequest) (*util.Empty, error) { + err := m.client.Call("Plugin.DestroyTarget", targetReq, new(util.Empty)) return new(util.Empty), err } -func (m *ProviderRPCClient) GetWorkspaceInfo(workspaceReq *WorkspaceRequest) (*workspace.WorkspaceInfo, error) { - var response workspace.WorkspaceInfo - err := m.client.Call("Plugin.GetWorkspaceInfo", workspaceReq, &response) - return &response, err +func (m *ProviderRPCClient) GetTargetProviderMetadata(targetReq *TargetRequest) (string, error) { + var resp string + err := m.client.Call("Plugin.GetTargetProviderMetadata", targetReq, &resp) + return resp, err } -func (m *ProviderRPCClient) CreateProject(projectReq *ProjectRequest) (*util.Empty, error) { - err := m.client.Call("Plugin.CreateProject", projectReq, new(util.Empty)) +func (m *ProviderRPCClient) CreateWorkspace(workspaceReq *WorkspaceRequest) (*util.Empty, error) { + err := m.client.Call("Plugin.CreateWorkspace", workspaceReq, new(util.Empty)) return new(util.Empty), err } -func (m *ProviderRPCClient) StartProject(projectReq *ProjectRequest) (*util.Empty, error) { - err := m.client.Call("Plugin.StartProject", projectReq, new(util.Empty)) +func (m *ProviderRPCClient) StartWorkspace(workspaceReq *WorkspaceRequest) (*util.Empty, error) { + err := m.client.Call("Plugin.StartWorkspace", workspaceReq, new(util.Empty)) return new(util.Empty), err } -func (m *ProviderRPCClient) StopProject(projectReq *ProjectRequest) (*util.Empty, error) { - err := m.client.Call("Plugin.StopProject", projectReq, new(util.Empty)) +func (m *ProviderRPCClient) StopWorkspace(workspaceReq *WorkspaceRequest) (*util.Empty, error) { + err := m.client.Call("Plugin.StopWorkspace", workspaceReq, new(util.Empty)) return new(util.Empty), err } -func (m *ProviderRPCClient) DestroyProject(projectReq *ProjectRequest) (*util.Empty, error) { - err := m.client.Call("Plugin.DestroyProject", projectReq, new(util.Empty)) +func (m *ProviderRPCClient) DestroyWorkspace(workspaceReq *WorkspaceRequest) (*util.Empty, error) { + err := m.client.Call("Plugin.DestroyWorkspace", workspaceReq, new(util.Empty)) return new(util.Empty), err } -func (m *ProviderRPCClient) GetProjectInfo(projectReq *ProjectRequest) (*project.ProjectInfo, error) { - var resp project.ProjectInfo - err := m.client.Call("Plugin.GetProjectInfo", projectReq, &resp) - return &resp, err +func (m *ProviderRPCClient) GetWorkspaceProviderMetadata(workspaceReq *WorkspaceRequest) (string, error) { + var resp string + err := m.client.Call("Plugin.GetWorkspaceProviderMetadata", workspaceReq, &resp) + return resp, err } diff --git a/pkg/provider/rpc_server.go b/pkg/provider/rpc_server.go index 251ae926d8..7855f7543d 100644 --- a/pkg/provider/rpc_server.go +++ b/pkg/provider/rpc_server.go @@ -4,9 +4,8 @@ package provider import ( + "github.com/daytonaio/daytona/pkg/models" "github.com/daytonaio/daytona/pkg/provider/util" - "github.com/daytonaio/daytona/pkg/workspace" - "github.com/daytonaio/daytona/pkg/workspace/project" ) type ProviderRPCServer struct { @@ -18,7 +17,7 @@ func (m *ProviderRPCServer) Initialize(arg InitializeProviderRequest, resp *util return err } -func (m *ProviderRPCServer) GetInfo(arg interface{}, resp *ProviderInfo) error { +func (m *ProviderRPCServer) GetInfo(arg interface{}, resp *models.ProviderInfo) error { info, err := m.Impl.GetInfo() if err != nil { return err @@ -37,82 +36,72 @@ func (m *ProviderRPCServer) CheckRequirements(arg interface{}, resp *[]Requireme return nil } -func (m *ProviderRPCServer) GetTargetManifest(arg interface{}, resp *ProviderTargetManifest) error { - targetManifest, err := m.Impl.GetTargetManifest() +func (m *ProviderRPCServer) GetPresetTargetConfigs(arg interface{}, resp *[]TargetConfig) error { + targetConfigs, err := m.Impl.GetPresetTargetConfigs() if err != nil { return err } - *resp = *targetManifest + *resp = *targetConfigs return nil } -func (m *ProviderRPCServer) GetPresetTargets(arg interface{}, resp *[]ProviderTarget) error { - targets, err := m.Impl.GetPresetTargets() - if err != nil { - return err - } - - *resp = *targets - return nil -} - -func (m *ProviderRPCServer) CreateWorkspace(arg *WorkspaceRequest, resp *util.Empty) error { - _, err := m.Impl.CreateWorkspace(arg) +func (m *ProviderRPCServer) CreateTarget(arg *TargetRequest, resp *util.Empty) error { + _, err := m.Impl.CreateTarget(arg) return err } -func (m *ProviderRPCServer) StartWorkspace(arg *WorkspaceRequest, resp *util.Empty) error { - _, err := m.Impl.StartWorkspace(arg) +func (m *ProviderRPCServer) StartTarget(arg *TargetRequest, resp *util.Empty) error { + _, err := m.Impl.StartTarget(arg) return err } -func (m *ProviderRPCServer) StopWorkspace(arg *WorkspaceRequest, resp *util.Empty) error { - _, err := m.Impl.StopWorkspace(arg) +func (m *ProviderRPCServer) StopTarget(arg *TargetRequest, resp *util.Empty) error { + _, err := m.Impl.StopTarget(arg) return err } -func (m *ProviderRPCServer) DestroyWorkspace(arg *WorkspaceRequest, resp *util.Empty) error { - _, err := m.Impl.DestroyWorkspace(arg) +func (m *ProviderRPCServer) DestroyTarget(arg *TargetRequest, resp *util.Empty) error { + _, err := m.Impl.DestroyTarget(arg) return err } -func (m *ProviderRPCServer) GetWorkspaceInfo(arg *WorkspaceRequest, resp *workspace.WorkspaceInfo) error { - info, err := m.Impl.GetWorkspaceInfo(arg) +func (m *ProviderRPCServer) GetTargetProviderMetadata(arg *TargetRequest, resp *string) error { + metadata, err := m.Impl.GetTargetProviderMetadata(arg) if err != nil { return err } - *resp = *info + *resp = metadata return nil } -func (m *ProviderRPCServer) CreateProject(arg *ProjectRequest, resp *util.Empty) error { - _, err := m.Impl.CreateProject(arg) +func (m *ProviderRPCServer) CreateWorkspace(arg *WorkspaceRequest, resp *util.Empty) error { + _, err := m.Impl.CreateWorkspace(arg) return err } -func (m *ProviderRPCServer) StartProject(arg *ProjectRequest, resp *util.Empty) error { - _, err := m.Impl.StartProject(arg) +func (m *ProviderRPCServer) StartWorkspace(arg *WorkspaceRequest, resp *util.Empty) error { + _, err := m.Impl.StartWorkspace(arg) return err } -func (m *ProviderRPCServer) StopProject(arg *ProjectRequest, resp *util.Empty) error { - _, err := m.Impl.StopProject(arg) +func (m *ProviderRPCServer) StopWorkspace(arg *WorkspaceRequest, resp *util.Empty) error { + _, err := m.Impl.StopWorkspace(arg) return err } -func (m *ProviderRPCServer) DestroyProject(arg *ProjectRequest, resp *util.Empty) error { - _, err := m.Impl.DestroyProject(arg) +func (m *ProviderRPCServer) DestroyWorkspace(arg *WorkspaceRequest, resp *util.Empty) error { + _, err := m.Impl.DestroyWorkspace(arg) return err } -func (m *ProviderRPCServer) GetProjectInfo(arg *ProjectRequest, resp *project.ProjectInfo) error { - info, err := m.Impl.GetProjectInfo(arg) +func (m *ProviderRPCServer) GetWorkspaceProviderMetadata(arg *WorkspaceRequest, resp *string) error { + metadata, err := m.Impl.GetWorkspaceProviderMetadata(arg) if err != nil { return err } - *resp = *info + *resp = metadata return nil } diff --git a/pkg/provider/store.go b/pkg/provider/store.go deleted file mode 100644 index 82aa0a2d6b..0000000000 --- a/pkg/provider/store.go +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package provider - -import "errors" - -type TargetFilter struct { - Name *string - Default *bool -} - -type TargetStore interface { - List(filter *TargetFilter) ([]*ProviderTarget, error) - Find(filter *TargetFilter) (*ProviderTarget, error) - Save(target *ProviderTarget) error - Delete(target *ProviderTarget) error -} - -var ( - ErrTargetNotFound = errors.New("target not found") -) - -func IsTargetNotFound(err error) bool { - return err.Error() == ErrTargetNotFound.Error() -} diff --git a/pkg/provider/types.go b/pkg/provider/types.go index dea970bbb4..d35cefd1fb 100644 --- a/pkg/provider/types.go +++ b/pkg/provider/types.go @@ -4,85 +4,42 @@ package provider import ( - "github.com/daytonaio/daytona/pkg/containerregistry" - "github.com/daytonaio/daytona/pkg/gitprovider" - "github.com/daytonaio/daytona/pkg/workspace" - "github.com/daytonaio/daytona/pkg/workspace/project" + "github.com/daytonaio/daytona/pkg/common" + "github.com/daytonaio/daytona/pkg/models" ) -type ProviderInfo struct { - Name string `json:"name" validate:"required"` - Label *string `json:"label" validate:"optional"` - Version string `json:"version" validate:"required"` -} - type InitializeProviderRequest struct { BasePath string DaytonaDownloadUrl string DaytonaVersion string - LogsDir string - - NetworkKey string - ServerUrl string - ApiUrl string + TargetLogsDir string + WorkspaceLogsDir string + NetworkKey string + ServerUrl string + ApiUrl string + ApiKey *string // ServerPort is used if the target supports direct server access ServerPort uint32 // ApiPort is used if the target supports direct server access ApiPort uint32 } -type WorkspaceRequest struct { - TargetOptions string - Workspace *workspace.Workspace +type TargetRequest struct { + Target *models.Target } -type ProjectRequest struct { - TargetOptions string - ContainerRegistry *containerregistry.ContainerRegistry - Project *project.Project - GitProviderConfig *gitprovider.GitProviderConfig - BuilderImage string - BuilderContainerRegistry *containerregistry.ContainerRegistry +type WorkspaceRequest struct { + BuilderImage string + ContainerRegistries common.ContainerRegistries + Workspace *models.Workspace + GitProviderConfig *models.GitProviderConfig } -type ProviderTarget struct { - Name string `json:"name" validate:"required"` - ProviderInfo ProviderInfo `json:"providerInfo" validate:"required"` +type TargetConfig struct { + Name string `json:"name" validate:"required"` // JSON encoded map of options - Options string `json:"options" validate:"required"` - IsDefault bool `json:"isDefault" validate:"required"` -} // @name ProviderTarget - -type ProviderTargetManifest map[string]ProviderTargetProperty // @name ProviderTargetManifest - -type ProviderTargetPropertyType string - -const ( - ProviderTargetPropertyTypeString ProviderTargetPropertyType = "string" - ProviderTargetPropertyTypeOption ProviderTargetPropertyType = "option" - ProviderTargetPropertyTypeBoolean ProviderTargetPropertyType = "boolean" - ProviderTargetPropertyTypeInt ProviderTargetPropertyType = "int" - ProviderTargetPropertyTypeFloat ProviderTargetPropertyType = "float" - ProviderTargetPropertyTypeFilePath ProviderTargetPropertyType = "file-path" -) - -type ProviderTargetProperty struct { - Type ProviderTargetPropertyType - InputMasked bool - // A regex string matched with the name of the target to determine if the property should be disabled - // If the regex matches the target name, the property will be disabled - // E.g. "^local$" will disable the property for the local target - DisabledPredicate string - // DefaultValue is converted into the appropriate type based on the Type - // If the property is a FilePath, the DefaultValue is a path to a directory - DefaultValue string - // Brief description of the property - Description string - // Options is only used if the Type is ProviderTargetPropertyTypeOption - Options []string - // Suggestions is an optional list of auto-complete values to assist the user while filling the field - Suggestions []string -} + Options string `json:"options" validate:"required"` +} // @name ProviderTargetConfig type RequirementStatus struct { Name string diff --git a/pkg/provider/util/project_start_script.go b/pkg/provider/util/workspace_start_script.go similarity index 96% rename from pkg/provider/util/project_start_script.go rename to pkg/provider/util/workspace_start_script.go index f3d86dfc11..837253509d 100644 --- a/pkg/provider/util/project_start_script.go +++ b/pkg/provider/util/workspace_start_script.go @@ -96,7 +96,7 @@ if test -n "$MISSING_DEPS"; then fi ` -func GetProjectStartScript(daytonaDownloadUrl string, apiKey string) string { +func GetWorkspaceStartScript(daytonaDownloadUrl string, apiKey string) string { return fmt.Sprintf(` %s # Download and install Daytona agent diff --git a/pkg/provisioner/create.go b/pkg/provisioner/create.go deleted file mode 100644 index dcd577844a..0000000000 --- a/pkg/provisioner/create.go +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package provisioner - -import ( - "github.com/daytonaio/daytona/pkg/provider" - "github.com/daytonaio/daytona/pkg/workspace" -) - -func (p *Provisioner) CreateWorkspace(workspace *workspace.Workspace, target *provider.ProviderTarget) error { - targetProvider, err := p.providerManager.GetProvider(target.ProviderInfo.Name) - if err != nil { - return err - } - - _, err = (*targetProvider).CreateWorkspace(&provider.WorkspaceRequest{ - TargetOptions: target.Options, - Workspace: workspace, - }) - - return err -} - -func (p *Provisioner) CreateProject(params ProjectParams) error { - targetProvider, err := p.providerManager.GetProvider(params.Target.ProviderInfo.Name) - if err != nil { - return err - } - - _, err = (*targetProvider).CreateProject(&provider.ProjectRequest{ - TargetOptions: params.Target.Options, - Project: params.Project, - ContainerRegistry: params.ContainerRegistry, - GitProviderConfig: params.GitProviderConfig, - BuilderImage: params.BuilderImage, - BuilderContainerRegistry: params.BuilderImageContainerRegistry, - }) - - return err -} diff --git a/pkg/provisioner/destroy.go b/pkg/provisioner/destroy.go deleted file mode 100644 index 4e965bf79d..0000000000 --- a/pkg/provisioner/destroy.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package provisioner - -import ( - "github.com/daytonaio/daytona/pkg/provider" - "github.com/daytonaio/daytona/pkg/workspace" - "github.com/daytonaio/daytona/pkg/workspace/project" -) - -func (p *Provisioner) DestroyWorkspace(workspace *workspace.Workspace, target *provider.ProviderTarget) error { - targetProvider, err := p.providerManager.GetProvider(target.ProviderInfo.Name) - if err != nil { - return err - } - - _, err = (*targetProvider).DestroyWorkspace(&provider.WorkspaceRequest{ - TargetOptions: target.Options, - Workspace: workspace, - }) - - return err -} - -func (p *Provisioner) DestroyProject(proj *project.Project, target *provider.ProviderTarget) error { - targetProvider, err := p.providerManager.GetProvider(target.ProviderInfo.Name) - if err != nil { - return err - } - - _, err = (*targetProvider).DestroyProject(&provider.ProjectRequest{ - TargetOptions: target.Options, - Project: proj, - }) - - return err -} diff --git a/pkg/provisioner/info.go b/pkg/provisioner/info.go deleted file mode 100644 index e926908c10..0000000000 --- a/pkg/provisioner/info.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package provisioner - -import ( - "context" - - "github.com/daytonaio/daytona/pkg/provider" - "github.com/daytonaio/daytona/pkg/workspace" -) - -type InfoResult struct { - Info *workspace.WorkspaceInfo - Err error -} - -// Gets the workspace info from the provider - the context is used to cancel the request if it takes too long -func (p *Provisioner) GetWorkspaceInfo(ctx context.Context, ws *workspace.Workspace, target *provider.ProviderTarget) (*workspace.WorkspaceInfo, error) { - ch := make(chan InfoResult, 1) - - go func() { - targetProvider, err := p.providerManager.GetProvider(target.ProviderInfo.Name) - if err != nil { - ch <- InfoResult{nil, err} - return - } - - info, err := (*targetProvider).GetWorkspaceInfo(&provider.WorkspaceRequest{ - TargetOptions: target.Options, - Workspace: ws, - }) - - ch <- InfoResult{info, err} - }() - - select { - case <-ctx.Done(): - return nil, ctx.Err() - case data := <-ch: - return data.Info, data.Err - } -} diff --git a/pkg/provisioner/provisioner.go b/pkg/provisioner/provisioner.go deleted file mode 100644 index e40d47a702..0000000000 --- a/pkg/provisioner/provisioner.go +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package provisioner - -import ( - "context" - - "github.com/daytonaio/daytona/pkg/containerregistry" - "github.com/daytonaio/daytona/pkg/gitprovider" - "github.com/daytonaio/daytona/pkg/provider" - "github.com/daytonaio/daytona/pkg/provider/manager" - "github.com/daytonaio/daytona/pkg/workspace" - "github.com/daytonaio/daytona/pkg/workspace/project" -) - -type ProjectParams struct { - Project *project.Project - Target *provider.ProviderTarget - ContainerRegistry *containerregistry.ContainerRegistry - GitProviderConfig *gitprovider.GitProviderConfig - BuilderImage string - BuilderImageContainerRegistry *containerregistry.ContainerRegistry -} - -type IProvisioner interface { - CreateProject(params ProjectParams) error - CreateWorkspace(workspace *workspace.Workspace, target *provider.ProviderTarget) error - DestroyProject(project *project.Project, target *provider.ProviderTarget) error - DestroyWorkspace(workspace *workspace.Workspace, target *provider.ProviderTarget) error - GetWorkspaceInfo(ctx context.Context, workspace *workspace.Workspace, target *provider.ProviderTarget) (*workspace.WorkspaceInfo, error) - StartProject(params ProjectParams) error - StartWorkspace(workspace *workspace.Workspace, target *provider.ProviderTarget) error - StopProject(project *project.Project, target *provider.ProviderTarget) error - StopWorkspace(workspace *workspace.Workspace, target *provider.ProviderTarget) error -} - -type ProvisionerConfig struct { - ProviderManager manager.IProviderManager -} - -func NewProvisioner(config ProvisionerConfig) IProvisioner { - return &Provisioner{ - providerManager: config.ProviderManager, - } -} - -type Provisioner struct { - providerManager manager.IProviderManager -} diff --git a/pkg/provisioner/start.go b/pkg/provisioner/start.go deleted file mode 100644 index 50033ddab3..0000000000 --- a/pkg/provisioner/start.go +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package provisioner - -import ( - "github.com/daytonaio/daytona/pkg/provider" - "github.com/daytonaio/daytona/pkg/workspace" -) - -func (p *Provisioner) StartWorkspace(workspace *workspace.Workspace, target *provider.ProviderTarget) error { - targetProvider, err := p.providerManager.GetProvider(target.ProviderInfo.Name) - if err != nil { - return err - } - - _, err = (*targetProvider).StartWorkspace(&provider.WorkspaceRequest{ - TargetOptions: target.Options, - Workspace: workspace, - }) - - return err -} - -func (p *Provisioner) StartProject(params ProjectParams) error { - targetProvider, err := p.providerManager.GetProvider(params.Target.ProviderInfo.Name) - if err != nil { - return err - } - - _, err = (*targetProvider).StartProject(&provider.ProjectRequest{ - TargetOptions: params.Target.Options, - Project: params.Project, - ContainerRegistry: params.ContainerRegistry, - GitProviderConfig: params.GitProviderConfig, - BuilderImage: params.BuilderImage, - BuilderContainerRegistry: params.BuilderImageContainerRegistry, - }) - - return err -} diff --git a/pkg/provisioner/stop.go b/pkg/provisioner/stop.go deleted file mode 100644 index 28f21c97ce..0000000000 --- a/pkg/provisioner/stop.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package provisioner - -import ( - "github.com/daytonaio/daytona/pkg/provider" - "github.com/daytonaio/daytona/pkg/workspace" - "github.com/daytonaio/daytona/pkg/workspace/project" -) - -func (p *Provisioner) StopWorkspace(workspace *workspace.Workspace, target *provider.ProviderTarget) error { - targetProvider, err := p.providerManager.GetProvider(target.ProviderInfo.Name) - if err != nil { - return err - } - - _, err = (*targetProvider).StopWorkspace(&provider.WorkspaceRequest{ - TargetOptions: target.Options, - Workspace: workspace, - }) - - return err -} - -func (p *Provisioner) StopProject(proj *project.Project, target *provider.ProviderTarget) error { - targetProvider, err := p.providerManager.GetProvider(target.ProviderInfo.Name) - if err != nil { - return err - } - - _, err = (*targetProvider).StopProject(&provider.ProjectRequest{ - TargetOptions: target.Options, - Project: proj, - }) - - return err -} diff --git a/pkg/runner/config.go b/pkg/runner/config.go new file mode 100644 index 0000000000..8f281da3f7 --- /dev/null +++ b/pkg/runner/config.go @@ -0,0 +1,210 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package runner + +import ( + "encoding/json" + "errors" + "os" + "path/filepath" + + "github.com/daytonaio/daytona/internal/util" + "github.com/daytonaio/daytona/pkg/logs" + "github.com/google/uuid" + + log "github.com/sirupsen/logrus" +) + +type Config struct { + Id string `json:"id"` + Name string `json:"name"` + ApiPort int32 `json:"apiPort"` + ServerApiKey string `json:"serverApiKey"` + ServerApiUrl string `json:"serverApiUrl"` + ProvidersDir string `json:"providersDir"` + LogFile *logs.LogFileConfig `json:"logFile"` + ClientId string `envconfig:"DAYTONA_CLIENT_ID"` + TelemetryEnabled bool `json:"telemetryEnabled"` +} // @name RunnerConfig + +var ErrConfigNotFound = errors.New("run 'daytona runner configure' to configure the runner") + +func GetConfig() (*Config, error) { + configFilePath, err := configFilePath() + if err != nil { + return nil, err + } + + _, err = os.Stat(configFilePath) + if os.IsNotExist(err) { + return nil, ErrConfigNotFound + } + + if err != nil { + return nil, err + } + + var c Config + configContent, err := os.ReadFile(configFilePath) + if err != nil { + return nil, err + } + + err = json.Unmarshal(configContent, &c) + if err != nil { + return nil, err + } + + if c.Id == "" { + c.Id = uuid.NewString() + } + + if c.ProvidersDir == "" { + defaultProvidersDir, err := getDefaultProvidersDir() + if err != nil { + return nil, err + } + + c.ProvidersDir = defaultProvidersDir + } + + if c.LogFile == nil { + logFilePath, err := getDefaultLogFilePath() + if err != nil { + log.Error("failed to get default log file path") + } + + c.LogFile = logs.GetDefaultLogFileConfig(logFilePath) + } + + err = Save(c) + if err != nil { + return nil, err + } + + return &c, nil +} + +func GetConfigDir() (string, error) { + daytonaConfigDir := os.Getenv("DAYTONA_RUNNER_CONFIG_DIR") + if daytonaConfigDir != "" { + return daytonaConfigDir, nil + } + + userConfigDir, err := os.UserConfigDir() + if err != nil { + return "", err + } + + return filepath.Join(userConfigDir, "daytona-runner"), nil +} + +func DeleteConfigDir() error { + configDir, err := GetConfigDir() + if err != nil { + return err + } + + return os.RemoveAll(configDir) +} + +func Save(c Config) error { + if c.ClientId == "" { + c.ClientId = uuid.NewString() + } + + if err := util.DirectoryValidator(&c.ProvidersDir); err != nil { + return err + } + + configFilePath, err := configFilePath() + if err != nil { + return err + } + + configContent, err := json.MarshalIndent(c, "", " ") + if err != nil { + return err + } + + err = os.MkdirAll(filepath.Dir(configFilePath), 0700) + if err != nil { + return err + } + + err = os.WriteFile(configFilePath, configContent, 0600) + if err != nil { + return err + } + + return nil +} + +func EnableTelemetry(c Config) error { + c.TelemetryEnabled = true + + return Save(c) +} + +func DisableTelemetry(c Config) error { + c.TelemetryEnabled = false + + return Save(c) +} + +func configFilePath() (string, error) { + configDir, err := GetConfigDir() + if err != nil { + return "", err + } + + return filepath.Join(configDir, "config.json"), nil +} + +func getDefaultLogFilePath() (string, error) { + configDir, err := GetConfigDir() + if err != nil { + return "", err + } + + return filepath.Join(configDir, "log"), nil +} + +func GetDefaultConfig() (*Config, error) { + providersDir, err := getDefaultProvidersDir() + if err != nil { + return nil, errors.New("failed to get default providers dir") + } + + logFilePath, err := getDefaultLogFilePath() + if err != nil { + log.Error("failed to get default log file path") + } + + c := Config{ + ProvidersDir: providersDir, + LogFile: logs.GetDefaultLogFileConfig(logFilePath), + TelemetryEnabled: true, + ApiPort: 3983, + } + + if os.Getenv("DEFAULT_PROVIDERS_DIR") != "" { + c.ProvidersDir = os.Getenv("DEFAULT_PROVIDERS_DIR") + } + + return &c, nil +} + +func getDefaultProvidersDir() (string, error) { + configDir, err := GetConfigDir() + if err != nil { + return "", err + } + + return filepath.Join(configDir, "providers"), nil +} + +func GetLogsDir(configDir string) string { + return filepath.Join(configDir, "logs") +} diff --git a/pkg/provider/manager/manifest.go b/pkg/runner/manifest.go similarity index 59% rename from pkg/provider/manager/manifest.go rename to pkg/runner/manifest.go index fe00fb815a..74a43e2ba1 100644 --- a/pkg/provider/manager/manifest.go +++ b/pkg/runner/manifest.go @@ -1,10 +1,18 @@ // Copyright 2024 Daytona Platforms Inc. // SPDX-License-Identifier: Apache-2.0 -package manager +package runner import ( + "encoding/json" + "fmt" + "io" + "net/http" + "slices" + "strings" + "github.com/daytonaio/daytona/pkg/os" + "github.com/daytonaio/daytona/pkg/services" "golang.org/x/mod/semver" ) @@ -20,6 +28,39 @@ type ProviderManifest struct { Versions map[string]Version `json:"versions"` } +func GetProvidersManifest(registryUrl string) (*ProvidersManifest, error) { + manifestUrl := fmt.Sprintf("%s/providers/manifest.json", registryUrl) + + resp, err := http.Get(manifestUrl) + if err != nil { + return nil, err + } + + defer resp.Body.Close() + + manifestJson, err := io.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + var manifest ProvidersManifest + err = json.Unmarshal(manifestJson, &manifest) + if err != nil { + return nil, err + } + + return &manifest, nil +} + +func GetProviderDownloadUrls(name, version, registryUrl string) (map[os.OperatingSystem]string, error) { + manifest, err := GetProvidersManifest(registryUrl) + if err != nil { + return nil, err + } + + return (*manifest)[name].Versions[version].DownloadUrls, nil +} + func (p *ProviderManifest) FindLatestVersion() (string, *Version) { var latestVersion string = "v0.0.0" @@ -88,3 +129,24 @@ func (m *ProvidersManifest) GetLatestVersions() *ProvidersManifest { return &latestManifest } + +func (m *ProvidersManifest) GetProviderListFromManifest() []services.ProviderDTO { + providerList := []services.ProviderDTO{} + for providerName, providerManifest := range *m { + latestVersion, _ := providerManifest.FindLatestVersion() + for version := range providerManifest.Versions { + providerList = append(providerList, services.ProviderDTO{ + Name: providerName, + Label: providerManifest.Label, + Version: version, + Latest: version == latestVersion, + }) + } + } + + slices.SortFunc(providerList, func(a, b services.ProviderDTO) int { + return strings.Compare(a.Name, b.Name) + }) + + return providerList +} diff --git a/pkg/provider/manager/error.go b/pkg/runner/providermanager/error.go similarity index 95% rename from pkg/provider/manager/error.go rename to pkg/runner/providermanager/error.go index e8faa1f393..1da18a57e8 100644 --- a/pkg/provider/manager/error.go +++ b/pkg/runner/providermanager/error.go @@ -1,7 +1,7 @@ // Copyright 2024 Daytona Platforms Inc. // SPDX-License-Identifier: Apache-2.0 -package manager +package providermanager import "fmt" diff --git a/pkg/provider/manager/installer.go b/pkg/runner/providermanager/installer.go similarity index 51% rename from pkg/provider/manager/installer.go rename to pkg/runner/providermanager/installer.go index 239928ee74..961e95a5ac 100644 --- a/pkg/provider/manager/installer.go +++ b/pkg/runner/providermanager/installer.go @@ -1,14 +1,10 @@ // Copyright 2024 Daytona Platforms Inc. // SPDX-License-Identifier: Apache-2.0 -package manager +package providermanager import ( "context" - "encoding/json" - "fmt" - "io" - "net/http" goos "os" "path/filepath" "runtime" @@ -17,31 +13,7 @@ import ( log "github.com/sirupsen/logrus" ) -func (m *ProviderManager) GetProvidersManifest() (*ProvidersManifest, error) { - manifestUrl := fmt.Sprintf("%s/providers/manifest.json", m.registryUrl) - - resp, err := http.Get(manifestUrl) - if err != nil { - return nil, err - } - - defer resp.Body.Close() - - manifestJson, err := io.ReadAll(resp.Body) - if err != nil { - return nil, err - } - - var manifest ProvidersManifest - err = json.Unmarshal(manifestJson, &manifest) - if err != nil { - return nil, err - } - - return &manifest, nil -} - -func (m *ProviderManager) DownloadProvider(ctx context.Context, downloadUrls map[os.OperatingSystem]string, providerName string) (string, error) { +func (m *providerManagerImpl) DownloadProvider(ctx context.Context, downloadUrls map[os.OperatingSystem]string, providerName string) (string, error) { downloadPath := filepath.Join(m.baseDir, providerName, providerName) if runtime.GOOS == "windows" { downloadPath += ".exe" diff --git a/pkg/provider/manager/manager.go b/pkg/runner/providermanager/manager.go similarity index 54% rename from pkg/provider/manager/manager.go rename to pkg/runner/providermanager/manager.go index 6f554f3af0..8cf7c759c6 100644 --- a/pkg/provider/manager/manager.go +++ b/pkg/runner/providermanager/manager.go @@ -1,7 +1,7 @@ // Copyright 2024 Daytona Platforms Inc. // SPDX-License-Identifier: Apache-2.0 -package manager +package providermanager import ( "context" @@ -14,9 +14,9 @@ import ( "strings" "github.com/daytonaio/daytona/internal/util" + "github.com/daytonaio/daytona/pkg/models" os_util "github.com/daytonaio/daytona/pkg/os" - . "github.com/daytonaio/daytona/pkg/provider" - "github.com/daytonaio/daytona/pkg/server/providertargets" + "github.com/daytonaio/daytona/pkg/provider" "github.com/hashicorp/go-hclog" "github.com/hashicorp/go-plugin" "github.com/shirou/gopsutil/process" @@ -39,9 +39,8 @@ var ProviderHandshakeConfig = plugin.HandshakeConfig{ type IProviderManager interface { DownloadProvider(ctx context.Context, downloadUrls map[os_util.OperatingSystem]string, providerName string) (string, error) - GetProvider(name string) (*Provider, error) - GetProviders() map[string]Provider - GetProvidersManifest() (*ProvidersManifest, error) + GetProvider(name string) (*provider.Provider, error) + GetProviders() map[string]provider.Provider RegisterProvider(pluginPath string, manualInstall bool) error TerminateProviderProcesses(providersBasePath string) error UninstallProvider(name string) error @@ -49,52 +48,79 @@ type IProviderManager interface { } type ProviderManagerConfig struct { + GetTargetConfigMap func(ctx context.Context) (map[string]*models.TargetConfig, error) + CreateTargetConfig func(ctx context.Context, name, options string, providerInfo models.ProviderInfo) error + CreateProviderNetworkKey func(ctx context.Context, providerName string) (string, error) + RunnerId string + RunnerName string DaytonaDownloadUrl string ServerUrl string - ServerVersion string ApiUrl string - LogsDir string - ProviderTargetService providertargets.IProviderTargetService - RegistryUrl string + ApiKey *string + WorkspaceLogsDir string + TargetLogsDir string BaseDir string - CreateProviderNetworkKey func(providerName string) (string, error) ServerPort uint32 ApiPort uint32 + Logger *log.Logger } -func NewProviderManager(config ProviderManagerConfig) *ProviderManager { - return &ProviderManager{ - pluginRefs: make(map[string]*pluginRef), - daytonaDownloadUrl: config.DaytonaDownloadUrl, - serverUrl: config.ServerUrl, - serverVersion: config.ServerVersion, - apiUrl: config.ApiUrl, - logsDir: config.LogsDir, - providerTargetService: config.ProviderTargetService, - registryUrl: config.RegistryUrl, - baseDir: config.BaseDir, - createProviderNetworkKey: config.CreateProviderNetworkKey, - serverPort: config.ServerPort, - apiPort: config.ApiPort, +var providerManager *providerManagerImpl + +func GetProviderManager(config *ProviderManagerConfig) *providerManagerImpl { + if config != nil && providerManager != nil { + config.Logger.Fatal("Provider manager already initialized") + } + + if providerManager == nil { + if config == nil { + log.Fatal("Provider manager not initialized") + } + + providerManager = &providerManagerImpl{ + pluginRefs: make(map[string]*pluginRef), + runnerId: config.RunnerId, + runnerName: config.RunnerName, + daytonaDownloadUrl: config.DaytonaDownloadUrl, + serverUrl: config.ServerUrl, + apiUrl: config.ApiUrl, + apiKey: config.ApiKey, + workspaceLogsDir: config.WorkspaceLogsDir, + targetLogsDir: config.TargetLogsDir, + getTargetConfigMap: config.GetTargetConfigMap, + createTargetConfig: config.CreateTargetConfig, + baseDir: config.BaseDir, + createProviderNetworkKey: config.CreateProviderNetworkKey, + serverPort: config.ServerPort, + apiPort: config.ApiPort, + logger: config.Logger, + } } + + return providerManager } -type ProviderManager struct { +type providerManagerImpl struct { + runnerId string + runnerName string pluginRefs map[string]*pluginRef + getTargetConfigMap func(ctx context.Context) (map[string]*models.TargetConfig, error) + createTargetConfig func(ctx context.Context, name, options string, providerInfo models.ProviderInfo) error + createProviderNetworkKey func(ctx context.Context, providerName string) (string, error) daytonaDownloadUrl string serverUrl string serverVersion string apiUrl string + apiKey *string serverPort uint32 apiPort uint32 - logsDir string - providerTargetService providertargets.IProviderTargetService - registryUrl string + workspaceLogsDir string + targetLogsDir string baseDir string - createProviderNetworkKey func(providerName string) (string, error) + logger *log.Logger } -func (m *ProviderManager) GetProvider(name string) (*Provider, error) { +func (m *providerManagerImpl) GetProvider(name string) (*provider.Provider, error) { pluginRef, ok := m.pluginRefs[name] if !ok { return nil, errors.New("provider not found") @@ -117,12 +143,12 @@ func (m *ProviderManager) GetProvider(name string) (*Provider, error) { return p, nil } -func (m *ProviderManager) GetProviders() map[string]Provider { - providers := make(map[string]Provider) +func (m *providerManagerImpl) GetProviders() map[string]provider.Provider { + providers := make(map[string]provider.Provider) for name := range m.pluginRefs { provider, err := m.GetProvider(name) if err != nil { - log.Printf("Error getting provider %s: %s", name, err) + m.logger.Printf("Error getting provider %s: %s", name, err) continue } @@ -132,7 +158,9 @@ func (m *ProviderManager) GetProviders() map[string]Provider { return providers } -func (m *ProviderManager) RegisterProvider(pluginPath string, manualInstall bool) error { +func (m *providerManagerImpl) RegisterProvider(pluginPath string, manualInstall bool) error { + ctx := context.Background() + pluginRef, err := m.initializeProvider(pluginPath) if err != nil { return err @@ -148,39 +176,47 @@ func (m *ProviderManager) RegisterProvider(pluginPath string, manualInstall bool return fmt.Errorf("failed to get provider: %w", err) } - existingTargets, err := m.providerTargetService.Map() + providerInfo, err := (*p).GetInfo() if err != nil { - return errors.New("failed to get targets: " + err.Error()) + return err + } + + existingTargetConfigs, err := m.getTargetConfigMap(ctx) + if err != nil { + return errors.New("failed to get target configs: " + err.Error()) } - presetTargets, err := (*p).GetPresetTargets() + presetTargetConfigs, err := (*p).GetPresetTargetConfigs() if err != nil { - return errors.New("failed to get preset targets: " + err.Error()) + return errors.New("failed to get preset target configs: " + err.Error()) } - log.Infof("Setting preset targets for %s", pluginRef.name) - for _, target := range *presetTargets { - if _, ok := existingTargets[target.Name]; ok { - log.Infof("Target %s already exists. Skipping...", target.Name) + m.logger.Infof("Setting preset target configs for %s", pluginRef.name) + for _, targetConfig := range *presetTargetConfigs { + if _, ok := existingTargetConfigs[targetConfig.Name]; ok { + m.logger.Infof("Target config %s already exists. Skipping...", targetConfig.Name) continue } - err := m.providerTargetService.Save(&target) + providerInfo.RunnerId = m.runnerId + providerInfo.RunnerName = m.runnerName + + err = m.createTargetConfig(ctx, targetConfig.Name, targetConfig.Options, providerInfo) if err != nil { - log.Errorf("Failed to set target %s: %s", target.Name, err) + m.logger.Errorf("Failed to set target config %s: %s", targetConfig.Name, err) } else { - log.Infof("Target %s set", target.Name) + m.logger.Infof("Target config %s set", targetConfig.Name) } } - log.Infof("Preset targets set for %s", pluginRef.name) + m.logger.Infof("Preset target configs set for %s", pluginRef.name) } - log.Infof("Provider %s initialized", pluginRef.name) + m.logger.Infof("Provider %s initialized", pluginRef.name) return nil } -func (m *ProviderManager) UninstallProvider(name string) error { +func (m *providerManagerImpl) UninstallProvider(name string) error { pluginRef, ok := m.pluginRefs[name] if !ok { return errors.New("provider not found") @@ -221,9 +257,8 @@ func (m *ProviderManager) UninstallProvider(name string) error { return nil } -func (m *ProviderManager) TerminateProviderProcesses(providersBasePath string) error { +func (m *providerManagerImpl) TerminateProviderProcesses(providersBasePath string) error { process, err := process.Processes() - if err != nil { return err } @@ -232,7 +267,7 @@ func (m *ProviderManager) TerminateProviderProcesses(providersBasePath string) e if e, err := p.Exe(); err == nil && strings.HasPrefix(e, providersBasePath) { err := p.Kill() if err != nil { - log.Errorf("Failed to kill process %d: %s", p.Pid, err) + m.logger.Errorf("Failed to kill process %d: %s", p.Pid, err) } } } @@ -240,7 +275,7 @@ func (m *ProviderManager) TerminateProviderProcesses(providersBasePath string) e return nil } -func (m *ProviderManager) Purge() error { +func (m *providerManagerImpl) Purge() error { for name := range m.pluginRefs { err := m.UninstallProvider(name) if err != nil { @@ -253,7 +288,9 @@ func (m *ProviderManager) Purge() error { return os.RemoveAll(m.baseDir) } -func (m *ProviderManager) initializeProvider(pluginPath string) (*pluginRef, error) { +func (m *providerManagerImpl) initializeProvider(pluginPath string) (*pluginRef, error) { + ctx := context.Background() + pluginName := filepath.Base(pluginPath) pluginBasePath := filepath.Dir(pluginPath) @@ -273,7 +310,7 @@ func (m *ProviderManager) initializeProvider(pluginPath string) (*pluginRef, err }) pluginMap := map[string]plugin.Plugin{} - pluginMap[pluginName] = &ProviderPlugin{} + pluginMap[pluginName] = &provider.ProviderPlugin{} client := plugin.NewClient(&plugin.ClientConfig{ HandshakeConfig: ProviderHandshakeConfig, @@ -283,25 +320,27 @@ func (m *ProviderManager) initializeProvider(pluginPath string) (*pluginRef, err Managed: true, }) - log.Infof("Provider %s registered", pluginName) + m.logger.Infof("Provider %s registered", pluginName) p, err := m.dispenseProvider(client, pluginName) if err != nil { return nil, errors.New("failed to initialize provider: " + err.Error()) } - networkKey, err := m.createProviderNetworkKey(pluginName) + networkKey, err := m.createProviderNetworkKey(ctx, pluginName) if err != nil { return nil, errors.New("failed to create network key: " + err.Error()) } - _, err = (*p).Initialize(InitializeProviderRequest{ + _, err = (*p).Initialize(provider.InitializeProviderRequest{ BasePath: pluginBasePath, DaytonaDownloadUrl: m.daytonaDownloadUrl, DaytonaVersion: m.serverVersion, ServerUrl: m.serverUrl, ApiUrl: m.apiUrl, - LogsDir: m.logsDir, + ApiKey: m.apiKey, + WorkspaceLogsDir: m.workspaceLogsDir, + TargetLogsDir: m.targetLogsDir, NetworkKey: networkKey, ServerPort: m.serverPort, ApiPort: m.apiPort, @@ -317,7 +356,7 @@ func (m *ProviderManager) initializeProvider(pluginPath string) (*pluginRef, err }, nil } -func (m *ProviderManager) dispenseProvider(client *plugin.Client, name string) (*Provider, error) { +func (m *providerManagerImpl) dispenseProvider(client *plugin.Client, name string) (*provider.Provider, error) { rpcClient, err := client.Client() if err != nil { return nil, err @@ -328,7 +367,7 @@ func (m *ProviderManager) dispenseProvider(client *plugin.Client, name string) ( return nil, err } - provider, ok := raw.(Provider) + provider, ok := raw.(provider.Provider) if !ok { return nil, errors.New("unexpected type from plugin") } diff --git a/pkg/runner/providers.go b/pkg/runner/providers.go new file mode 100644 index 0000000000..a11421546f --- /dev/null +++ b/pkg/runner/providers.go @@ -0,0 +1,141 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package runner + +import ( + "context" + "errors" + "os" + "path/filepath" + + "github.com/daytonaio/daytona/pkg/runner/providermanager" +) + +func (r *Runner) downloadDefaultProviders(registryUrl string) error { + manifest, err := GetProvidersManifest(registryUrl) + if err != nil { + return err + } + + defaultProviders := manifest.GetDefaultProviders() + + r.logger.Info("Downloading default providers") + for providerName, provider := range defaultProviders { + lockFilePath := filepath.Join(r.Config.ProvidersDir, providerName, providermanager.INITIAL_SETUP_LOCK_FILE_NAME) + + _, err := os.Stat(lockFilePath) + if err == nil { + continue + } + + _, err = r.providerManager.DownloadProvider(context.Background(), provider.DownloadUrls, providerName) + if err != nil { + if !providermanager.IsProviderAlreadyDownloaded(err, providerName) { + r.logger.Error(err) + } + continue + } + } + + r.logger.Info("Default providers downloaded") + + return nil +} + +func (r *Runner) registerProviders(registryUrl string) error { + r.logger.Info("Registering providers") + + manifest, err := GetProvidersManifest(registryUrl) + if err != nil { + return err + } + + directoryEntries, err := os.ReadDir(r.Config.ProvidersDir) + if err != nil { + if os.IsNotExist(err) { + r.logger.Info("No providers found") + return nil + } + return err + } + + for _, entry := range directoryEntries { + if entry.IsDir() { + providerDir := filepath.Join(r.Config.ProvidersDir, entry.Name()) + + pluginPath, err := r.getPluginPath(providerDir) + if err != nil { + if !providermanager.IsNoPluginFound(err, providerDir) { + r.logger.Error(err) + } + continue + } + + err = r.providerManager.RegisterProvider(pluginPath, false) + if err != nil { + r.logger.Error(err) + continue + } + + // Lock the initial setup + lockFilePath := filepath.Join(r.Config.ProvidersDir, entry.Name(), providermanager.INITIAL_SETUP_LOCK_FILE_NAME) + + _, err = os.Stat(lockFilePath) + if err != nil { + file, err := os.Create(lockFilePath) + if err != nil { + return err + } + defer file.Close() + } + + // Check for updates + provider, err := r.providerManager.GetProvider(entry.Name()) + if err != nil { + r.logger.Error(err) + continue + } + + info, err := (*provider).GetInfo() + if err != nil { + r.logger.Error(err) + continue + } + requirements, err := (*provider).CheckRequirements() + if err != nil { + return err + } + for _, req := range *requirements { + if req.Met { + r.logger.Infof("Provider requirement met: %s", req.Reason) + } else { + r.logger.Warnf("Provider requirement not met: %s", req.Reason) + } + } + + if manifest.HasUpdateAvailable(info.Name, info.Version) { + r.logger.Infof("Update available for %s. Update with `daytona provider update`.", info.Name) + } + } + } + + r.logger.Info("Providers registered") + + return nil +} + +func (r *Runner) getPluginPath(dir string) (string, error) { + files, err := os.ReadDir(dir) + if err != nil { + return "", err + } + + for _, file := range files { + if !file.IsDir() && file.Name() != providermanager.INITIAL_SETUP_LOCK_FILE_NAME { + return filepath.Join(dir, file.Name()), nil + } + } + + return "", errors.New("no plugin found in " + dir) +} diff --git a/pkg/runner/runner.go b/pkg/runner/runner.go new file mode 100644 index 0000000000..f92a4f147e --- /dev/null +++ b/pkg/runner/runner.go @@ -0,0 +1,336 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package runner + +import ( + "context" + "errors" + "fmt" + "net" + "net/http" + "os" + "os/signal" + "time" + + "github.com/daytonaio/daytona/internal/constants" + "github.com/daytonaio/daytona/internal/util" + "github.com/daytonaio/daytona/pkg/api/controllers/health" + "github.com/daytonaio/daytona/pkg/jobs" + "github.com/daytonaio/daytona/pkg/jobs/build" + "github.com/daytonaio/daytona/pkg/jobs/runner" + "github.com/daytonaio/daytona/pkg/jobs/target" + "github.com/daytonaio/daytona/pkg/jobs/workspace" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/runner/providermanager" + "github.com/daytonaio/daytona/pkg/telemetry" + "github.com/gin-gonic/gin" + "github.com/hashicorp/go-plugin" + log "github.com/sirupsen/logrus" +) + +const RUNNER_METADATA_UPDATE_INTERVAL = 2 * time.Second + +type IRunner interface { + Start(ctx context.Context) error + CheckAndRunJobs(ctx context.Context) error + Purge(ctx context.Context) error +} + +type RunnerConfig struct { + models.Runner + Config *Config + Logger *log.Logger + + ProviderManager providermanager.IProviderManager + RegistryUrl string + + ListPendingJobs func(ctx context.Context) ([]*models.Job, int, error) + UpdateJobState func(ctx context.Context, jobId string, state models.JobState, err error) error + SetRunnerMetadata func(ctx context.Context, runnerId string, metadata models.RunnerMetadata) error + TrackTelemetryEvent func(event telemetry.Event, clientId string) error + + WorkspaceJobFactory workspace.IWorkspaceJobFactory + TargetJobFactory target.ITargetJobFactory + BuildJobFactory build.IBuildJobFactory + RunnerJobFactory runner.IRunnerJobFactory +} + +func NewRunner(config RunnerConfig) IRunner { + return &Runner{ + Runner: config.Runner, + Config: config.Config, + logger: config.Logger, + + providerManager: config.ProviderManager, + registryUrl: config.RegistryUrl, + + listPendingJobs: config.ListPendingJobs, + updateJobState: config.UpdateJobState, + setRunnerMetadata: config.SetRunnerMetadata, + trackTelemetryEvent: config.TrackTelemetryEvent, + + workspaceJobFactory: config.WorkspaceJobFactory, + targetJobFactory: config.TargetJobFactory, + buildJobFactory: config.BuildJobFactory, + runnerJobFactory: config.RunnerJobFactory, + } +} + +type Runner struct { + models.Runner + Config *Config + logger *log.Logger + startTime time.Time + + providerManager providermanager.IProviderManager + registryUrl string + + listPendingJobs func(ctx context.Context) ([]*models.Job, int, error) + updateJobState func(ctx context.Context, jobId string, state models.JobState, err error) error + setRunnerMetadata func(ctx context.Context, runnerId string, metadata models.RunnerMetadata) error + trackTelemetryEvent func(event telemetry.Event, clientId string) error + + workspaceJobFactory workspace.IWorkspaceJobFactory + targetJobFactory target.ITargetJobFactory + buildJobFactory build.IBuildJobFactory + runnerJobFactory runner.IRunnerJobFactory +} + +func (r *Runner) Start(ctx context.Context) error { + r.logger.Info(fmt.Sprintf("Starting runner %s\n", r.Config.Id)) + + r.startTime = time.Now() + + // Check if the API port is already in use for the runner API server + _, err := net.Dial("tcp", fmt.Sprintf(":%d", r.Config.ApiPort)) + if err == nil { + return fmt.Errorf("cannot start runner API server, port %d is already in use", r.Config.ApiPort) + } + + go func() { + interruptChannel := make(chan os.Signal, 1) + signal.Notify(interruptChannel, os.Interrupt) + + for range interruptChannel { + plugin.CleanupClients() + } + }() + + router := gin.New() + router.Use(gin.Recovery()) + + gin.SetMode(gin.ReleaseMode) + + public := router.Group("/") + + healthController := public.Group(constants.HEALTH_CHECK_ROUTE) + { + healthController.GET("", health.HealthCheck) + } + + routerErrChan := make(chan error) + go func() { + routerErrChan <- router.Run(fmt.Sprintf(":%d", r.Config.ApiPort)) + }() + + // Terminate orphaned provider processes + err = r.providerManager.TerminateProviderProcesses(r.Config.ProvidersDir) + if err != nil { + r.logger.Errorf("Failed to terminate orphaned provider processes: %s", err) + } + + err = r.downloadDefaultProviders(r.registryUrl) + if err != nil { + return err + } + + err = r.registerProviders(r.registryUrl) + if err != nil { + return err + } + + go func() { + for { + err := r.CheckAndRunJobs(ctx) + if err != nil { + r.logger.Error(err) + // Handle the function continuously erroring (e.g. authentication) + time.Sleep(3 * time.Second) + } + } + }() + + go func() { + for { + _ = r.UpdateRunnerMetadata(r.Config) + time.Sleep(RUNNER_METADATA_UPDATE_INTERVAL) + } + }() + + r.logger.Info("Runner started") + + select { + case err = <-routerErrChan: + case <-ctx.Done(): + err = nil + } + + r.logger.Info("Shutting down runner") + return err +} + +func (r *Runner) CheckAndRunJobs(ctx context.Context) error { + jobs, statusCode, err := r.listPendingJobs(ctx) + if err != nil { + if statusCode == http.StatusNotFound { + return nil + } + return err + } + + for _, j := range jobs { + if j.State != models.JobStatePending { + continue + } + + j.State = models.JobStateRunning + err := r.updateJobState(ctx, j.Id, models.JobStateRunning, nil) + if err != nil { + r.logger.Trace(err) + continue + } + + r.logJobStateUpdate(j, nil) + go r.runJob(ctx, j) + } + + return nil +} + +func (r *Runner) Purge(ctx context.Context) error { + return r.providerManager.Purge() +} + +func (r *Runner) runJob(ctx context.Context, j *models.Job) { + startTime := time.Now() + if r.Config.TelemetryEnabled { + event := telemetry.NewJobEvent(telemetry.JobEventRunStarted, j, nil, nil) + err := r.trackTelemetryEvent(event, r.Config.ClientId) + if err != nil { + r.logger.Trace(err) + } + } + + var job jobs.IJob + + switch j.ResourceType { + case models.ResourceTypeWorkspace: + job = r.workspaceJobFactory.Create(*j) + case models.ResourceTypeTarget: + job = r.targetJobFactory.Create(*j) + case models.ResourceTypeBuild: + job = r.buildJobFactory.Create(*j) + case models.ResourceTypeRunner: + job = r.runnerJobFactory.Create(*j) + default: + r.handleRunFailed(j, errors.New("invalid resource type for job"), startTime) + return + } + + err := job.Execute(ctx) + if err != nil { + r.handleRunFailed(j, err, startTime) + return + } + + j.State = models.JobStateSuccess + r.logJobStateUpdate(j, nil) + err = r.updateJobState(ctx, j.Id, models.JobStateSuccess, nil) + if err != nil { + r.handleRunFailed(j, err, startTime) + return + } + + if r.Config.TelemetryEnabled { + execTime := time.Since(startTime) + event := telemetry.NewJobEvent(telemetry.JobEventRunCompleted, j, nil, map[string]interface{}{"exec_time_ms": execTime.Milliseconds()}) + err = r.trackTelemetryEvent(event, r.Config.ClientId) + if err != nil { + r.logger.Trace(err) + } + } +} + +// Runner uptime in seconds +func (r *Runner) uptime() int32 { + return max(int32(time.Since(r.startTime).Seconds()), 1) +} + +func (r *Runner) UpdateRunnerMetadata(config *Config) error { + providers := r.providerManager.GetProviders() + uptime := r.uptime() + + providerInfos := []models.ProviderInfo{} + for _, provider := range providers { + info, err := provider.GetInfo() + if err != nil { + r.logger.Info(fmt.Errorf("failed to get provider: %w", err)) + continue + } + + info.RunnerId = r.Config.Id + info.RunnerName = r.Config.Name + providerInfos = append(providerInfos, info) + } + + return r.setRunnerMetadata(context.Background(), r.Config.Id, models.RunnerMetadata{ + Uptime: uint64(uptime), + Providers: providerInfos, + RunningJobs: util.Pointer(uint64(0)), + }) +} + +func (r *Runner) logJobStateUpdate(j *models.Job, err error) { + if j == nil { + return + } + + message := "Invalid Job State" + switch j.State { + case models.JobStatePending: + message = "Job pending" + case models.JobStateSuccess: + message = "Job succeeded" + case models.JobStateError: + message = "Job failed" + case models.JobStateRunning: + message = "Running job" + } + + message = fmt.Sprintf("%-16s %-16s %-12s %-12s\n", message, j.Id, j.ResourceType, j.Action) + if err != nil { + message += fmt.Sprintf(" Error: %s\n", err) + } + + r.logger.Info(message) +} + +func (r *Runner) handleRunFailed(j *models.Job, err error, startTime time.Time) { + j.State = models.JobStateError + r.logJobStateUpdate(j, err) + + if r.Config.TelemetryEnabled { + execTime := time.Since(startTime) + event := telemetry.NewJobEvent(telemetry.JobEventRunFailed, j, err, map[string]interface{}{"exec_time_ms": execTime.Milliseconds()}) + telemetryErr := r.trackTelemetryEvent(event, r.Config.ClientId) + if telemetryErr != nil { + r.logger.Trace(telemetryErr) + } + } + + updateJobErr := r.updateJobState(context.Background(), j.Id, models.JobStateError, err) + if updateJobErr != nil { + r.logger.Error(updateJobErr) + } +} diff --git a/pkg/build/scheduler.go b/pkg/scheduler/cron.go similarity index 97% rename from pkg/build/scheduler.go rename to pkg/scheduler/cron.go index 6c17be9323..6c81156c04 100644 --- a/pkg/build/scheduler.go +++ b/pkg/scheduler/cron.go @@ -1,7 +1,7 @@ // Copyright 2024 Daytona Platforms Inc. // SPDX-License-Identifier: Apache-2.0 -package build +package scheduler import ( "github.com/robfig/cron/v3" diff --git a/pkg/server/apikeys/apikeys.go b/pkg/server/apikeys/apikeys.go index fc46dcea00..cf4ef837e5 100644 --- a/pkg/server/apikeys/apikeys.go +++ b/pkg/server/apikeys/apikeys.go @@ -4,49 +4,89 @@ package apikeys import ( - "github.com/daytonaio/daytona/internal/apikeys" - "github.com/daytonaio/daytona/pkg/apikey" + "context" + + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/services" + "github.com/daytonaio/daytona/pkg/telemetry" + log "github.com/sirupsen/logrus" ) -func (s *ApiKeyService) ListClientKeys() ([]*apikey.ApiKey, error) { - keys, err := s.apiKeyStore.List() +func (s *ApiKeyService) ListClientKeys(ctx context.Context) ([]*services.ApiKeyDTO, error) { + keys, err := s.apiKeyStore.List(ctx) if err != nil { return nil, err } - clientKeys := []*apikey.ApiKey{} + clientKeys := []*services.ApiKeyDTO{} for _, key := range keys { - if key.Type == apikey.ApiKeyTypeClient { - clientKeys = append(clientKeys, key) + if key.Type == models.ApiKeyTypeClient { + clientKeys = append(clientKeys, &services.ApiKeyDTO{ + Type: key.Type, + Name: key.Name, + }) } } return clientKeys, nil } -func (s *ApiKeyService) Revoke(name string) error { - apiKey, err := s.apiKeyStore.FindByName(name) +func (s *ApiKeyService) Delete(ctx context.Context, name string) error { + apiKey, err := s.apiKeyStore.FindByName(ctx, name) if err != nil { return err } - return s.apiKeyStore.Delete(apiKey) + return s.apiKeyStore.Delete(ctx, apiKey) } -func (s *ApiKeyService) Generate(keyType apikey.ApiKeyType, name string) (string, error) { - key := apikeys.GenerateRandomKey() +func (s *ApiKeyService) Create(ctx context.Context, keyType models.ApiKeyType, name string) (string, error) { + key := s.generateRandomKey(name) - apiKey := &apikey.ApiKey{ - KeyHash: apikeys.HashKey(key), + apiKey := &models.ApiKey{ + KeyHash: s.getKeyHash(key), Type: keyType, Name: name, } - err := s.apiKeyStore.Save(apiKey) + err := s.apiKeyStore.Save(ctx, apiKey) + if err != nil { + return "", s.handleCreateApiKeyError(ctx, apiKey, err) + } + + return key, s.handleCreateApiKeyError(ctx, apiKey, nil) +} + +func (s *ApiKeyService) GetApiKeyName(ctx context.Context, apiKey string) (string, error) { + key, err := s.apiKeyStore.Find(ctx, s.getKeyHash(apiKey)) if err != nil { return "", err } - return key, nil + return key.Name, nil +} + +func (s *ApiKeyService) handleCreateApiKeyError(ctx context.Context, key *models.ApiKey, err error) error { + if key.Type != models.ApiKeyTypeClient { + return err + } + + if !telemetry.TelemetryEnabled(ctx) { + return err + } + + eventName := telemetry.ApiKeyEventLifecycleCreated + if err != nil { + eventName = telemetry.ApiKeyEventLifecycleCreationFailed + } + + event := telemetry.NewApiKeyEvent(eventName, key, err, nil) + + telemetryErr := s.trackTelemetryEvent(event, telemetry.ClientId(ctx)) + if telemetryErr != nil { + log.Trace(telemetryErr) + } + + return err } diff --git a/pkg/server/apikeys/apikeys_test.go b/pkg/server/apikeys/apikeys_test.go index 9e88b26786..3c427c6e5e 100644 --- a/pkg/server/apikeys/apikeys_test.go +++ b/pkg/server/apikeys/apikeys_test.go @@ -3,55 +3,63 @@ package apikeys_test -import "github.com/daytonaio/daytona/pkg/apikey" +import ( + "context" + + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/services" +) func (s *ApiKeyServiceTestSuite) TestListClientKeys() { - expectedKeys := []*apikey.ApiKey{} + expectedKeys := []*services.ApiKeyDTO{} keyNames := []string{} keyNames = append(keyNames, clientKeyNames...) for _, keyName := range keyNames { - apiKey, _ := s.apiKeyStore.FindByName(keyName) - expectedKeys = append(expectedKeys, apiKey) + apiKey, _ := s.apiKeyStore.FindByName(context.TODO(), keyName) + expectedKeys = append(expectedKeys, &services.ApiKeyDTO{ + Type: apiKey.Type, + Name: apiKey.Name, + }) } require := s.Require() - keys, err := s.apiKeyService.ListClientKeys() + keys, err := s.apiKeyService.ListClientKeys(context.TODO()) require.Nil(err) require.ElementsMatch(expectedKeys, keys) } func (s *ApiKeyServiceTestSuite) TestRevoke() { - expectedKeys := []*apikey.ApiKey{} + expectedKeys := []*models.ApiKey{} keyNames := []string{} keyNames = append(keyNames, clientKeyNames[1:]...) - keyNames = append(keyNames, projectKeyNames...) + keyNames = append(keyNames, workspaceKeyNames...) for _, keyName := range keyNames { - apiKey, _ := s.apiKeyStore.FindByName(keyName) + apiKey, _ := s.apiKeyStore.FindByName(context.TODO(), keyName) expectedKeys = append(expectedKeys, apiKey) } require := s.Require() - err := s.apiKeyService.Revoke(clientKeyNames[0]) + err := s.apiKeyService.Delete(context.TODO(), clientKeyNames[0]) require.Nil(err) - keys, err := s.apiKeyStore.List() + keys, err := s.apiKeyStore.List(context.TODO()) require.Nil(err) require.ElementsMatch(expectedKeys, keys) } func (s *ApiKeyServiceTestSuite) TestGenerate() { - expectedKeys := []*apikey.ApiKey{} + expectedKeys := []*models.ApiKey{} keyNames := []string{} keyNames = append(keyNames, clientKeyNames...) - keyNames = append(keyNames, projectKeyNames...) + keyNames = append(keyNames, workspaceKeyNames...) for _, keyName := range keyNames { - apiKey, _ := s.apiKeyStore.FindByName(keyName) + apiKey, _ := s.apiKeyStore.FindByName(context.TODO(), keyName) expectedKeys = append(expectedKeys, apiKey) } @@ -59,14 +67,14 @@ func (s *ApiKeyServiceTestSuite) TestGenerate() { require := s.Require() - _, err := s.apiKeyService.Generate(apikey.ApiKeyTypeClient, keyName) + _, err := s.apiKeyService.Create(context.TODO(), models.ApiKeyTypeClient, keyName) require.Nil(err) - apiKey, err := s.apiKeyStore.FindByName(keyName) + apiKey, err := s.apiKeyStore.FindByName(context.TODO(), keyName) require.Nil(err) expectedKeys = append(expectedKeys, apiKey) - apiKeys, err := s.apiKeyStore.List() + apiKeys, err := s.apiKeyStore.List(context.TODO()) require.Nil(err) require.ElementsMatch(expectedKeys, apiKeys) } diff --git a/pkg/server/apikeys/service.go b/pkg/server/apikeys/service.go index 42bb25ebb2..270ab134ff 100644 --- a/pkg/server/apikeys/service.go +++ b/pkg/server/apikeys/service.go @@ -3,27 +3,31 @@ package apikeys -import "github.com/daytonaio/daytona/pkg/apikey" - -type IApiKeyService interface { - Generate(keyType apikey.ApiKeyType, name string) (string, error) - IsProjectApiKey(apiKey string) bool - IsWorkspaceApiKey(apiKey string) bool - IsValidApiKey(apiKey string) bool - ListClientKeys() ([]*apikey.ApiKey, error) - Revoke(name string) error -} +import ( + "github.com/daytonaio/daytona/pkg/services" + "github.com/daytonaio/daytona/pkg/stores" + "github.com/daytonaio/daytona/pkg/telemetry" +) type ApiKeyServiceConfig struct { - ApiKeyStore apikey.Store + ApiKeyStore stores.ApiKeyStore + GenerateRandomKey func(name string) string + GetKeyHash func(key string) string + TrackTelemetryEvent func(event telemetry.Event, clientId string) error } -func NewApiKeyService(config ApiKeyServiceConfig) IApiKeyService { +func NewApiKeyService(config ApiKeyServiceConfig) services.IApiKeyService { return &ApiKeyService{ - apiKeyStore: config.ApiKeyStore, + apiKeyStore: config.ApiKeyStore, + generateRandomKey: config.GenerateRandomKey, + getKeyHash: config.GetKeyHash, + trackTelemetryEvent: config.TrackTelemetryEvent, } } type ApiKeyService struct { - apiKeyStore apikey.Store + apiKeyStore stores.ApiKeyStore + generateRandomKey func(name string) string + getKeyHash func(key string) string + trackTelemetryEvent func(event telemetry.Event, clientId string) error } diff --git a/pkg/server/apikeys/service_test.go b/pkg/server/apikeys/service_test.go index cb6f74849d..2fc87546e2 100644 --- a/pkg/server/apikeys/service_test.go +++ b/pkg/server/apikeys/service_test.go @@ -4,21 +4,27 @@ package apikeys_test import ( + "context" "testing" + apikeys_util "github.com/daytonaio/daytona/internal/apikeys" t_apikeys "github.com/daytonaio/daytona/internal/testing/server/apikeys" - "github.com/daytonaio/daytona/pkg/apikey" + + "github.com/daytonaio/daytona/pkg/models" "github.com/daytonaio/daytona/pkg/server/apikeys" + "github.com/daytonaio/daytona/pkg/services" + "github.com/daytonaio/daytona/pkg/stores" + "github.com/daytonaio/daytona/pkg/telemetry" "github.com/stretchr/testify/suite" ) var clientKeyNames []string = []string{"client1", "client2", "client3"} -var projectKeyNames []string = []string{"project1", "project2"} +var workspaceKeyNames []string = []string{"workspace1", "workspace2"} type ApiKeyServiceTestSuite struct { suite.Suite - apiKeyService apikeys.IApiKeyService - apiKeyStore apikey.Store + apiKeyService services.IApiKeyService + apiKeyStore stores.ApiKeyStore } func NewApiKeyServiceTestSuite() *ApiKeyServiceTestSuite { @@ -29,14 +35,23 @@ func (s *ApiKeyServiceTestSuite) SetupTest() { s.apiKeyStore = t_apikeys.NewInMemoryApiKeyStore() s.apiKeyService = apikeys.NewApiKeyService(apikeys.ApiKeyServiceConfig{ ApiKeyStore: s.apiKeyStore, + GenerateRandomKey: func(name string) string { + return apikeys_util.GenerateRandomKey() + }, + GetKeyHash: func(key string) string { + return apikeys_util.HashKey(key) + }, + TrackTelemetryEvent: func(event telemetry.Event, clientId string) error { + return nil + }, }) for _, keyName := range clientKeyNames { - _, _ = s.apiKeyService.Generate(apikey.ApiKeyTypeClient, keyName) + _, _ = s.apiKeyService.Create(context.TODO(), models.ApiKeyTypeClient, keyName) } - for _, keyName := range projectKeyNames { - _, _ = s.apiKeyService.Generate(apikey.ApiKeyTypeProject, keyName) + for _, keyName := range workspaceKeyNames { + _, _ = s.apiKeyService.Create(context.TODO(), models.ApiKeyTypeWorkspace, keyName) } } diff --git a/pkg/server/apikeys/validate.go b/pkg/server/apikeys/validate.go index 89454bc8ec..2936fbb4a8 100644 --- a/pkg/server/apikeys/validate.go +++ b/pkg/server/apikeys/validate.go @@ -4,41 +4,38 @@ package apikeys import ( - "github.com/daytonaio/daytona/internal/apikeys" - "github.com/daytonaio/daytona/pkg/apikey" + "context" + + "github.com/daytonaio/daytona/pkg/models" ) -func (s *ApiKeyService) IsValidApiKey(apiKey string) bool { - keyHash := apikeys.HashKey(apiKey) +func (s *ApiKeyService) IsValidApiKey(ctx context.Context, apiKey string) bool { + keyHash := s.getKeyHash(apiKey) - _, err := s.apiKeyStore.Find(keyHash) + _, err := s.apiKeyStore.Find(ctx, keyHash) return err == nil } -func (s *ApiKeyService) IsProjectApiKey(apiKey string) bool { - keyHash := apikeys.HashKey(apiKey) +func (s *ApiKeyService) GetApiKeyType(ctx context.Context, apiKey string) (models.ApiKeyType, error) { + keyHash := s.getKeyHash(apiKey) - key, err := s.apiKeyStore.Find(keyHash) + key, err := s.apiKeyStore.Find(ctx, keyHash) if err != nil { - return false - } - - if key.Type != apikey.ApiKeyTypeProject { - return false + return models.ApiKeyTypeClient, err } - return true + return key.Type, nil } -func (s *ApiKeyService) IsWorkspaceApiKey(apiKey string) bool { - keyHash := apikeys.HashKey(apiKey) +func (s *ApiKeyService) IsTargetApiKey(ctx context.Context, apiKey string) bool { + keyHash := s.getKeyHash(apiKey) - key, err := s.apiKeyStore.Find(keyHash) + key, err := s.apiKeyStore.Find(ctx, keyHash) if err != nil { return false } - if key.Type != apikey.ApiKeyTypeWorkspace { + if key.Type != models.ApiKeyTypeTarget { return false } diff --git a/pkg/server/apikeys/validate_test.go b/pkg/server/apikeys/validate_test.go index 003090cdce..ff13380404 100644 --- a/pkg/server/apikeys/validate_test.go +++ b/pkg/server/apikeys/validate_test.go @@ -3,17 +3,21 @@ package apikeys_test -import "github.com/daytonaio/daytona/pkg/apikey" +import ( + "context" + + "github.com/daytonaio/daytona/pkg/models" +) func (s *ApiKeyServiceTestSuite) TestIsValidKey_True() { keyName := "api-key" require := s.Require() - apiKey, err := s.apiKeyService.Generate(apikey.ApiKeyTypeProject, keyName) + apiKey, err := s.apiKeyService.Create(context.TODO(), models.ApiKeyTypeWorkspace, keyName) require.Nil(err) - res := s.apiKeyService.IsValidApiKey(apiKey) + res := s.apiKeyService.IsValidApiKey(context.TODO(), apiKey) require.True(res) } @@ -22,54 +26,19 @@ func (s *ApiKeyServiceTestSuite) TestIsValidKey_False() { require := s.Require() - res := s.apiKeyService.IsValidApiKey(unknownKey) + res := s.apiKeyService.IsValidApiKey(context.TODO(), unknownKey) require.False(res) } -func (s *ApiKeyServiceTestSuite) TestIsProjectApiKey_True() { - keyName := "projectKey" - - require := s.Require() - - apiKey, err := s.apiKeyService.Generate(apikey.ApiKeyTypeProject, keyName) - require.Nil(err) - - res := s.apiKeyService.IsProjectApiKey(apiKey) - require.True(res) -} - -func (s *ApiKeyServiceTestSuite) TestIsProjectApiKey_False() { - keyName := "clientKey" - - require := s.Require() - - apiKey, err := s.apiKeyService.Generate(apikey.ApiKeyTypeClient, keyName) - require.Nil(err) - - res := s.apiKeyService.IsProjectApiKey(apiKey) - require.False(res) -} - -func (s *ApiKeyServiceTestSuite) TestIsWorkspaceApiKey_True() { +func (s *ApiKeyServiceTestSuite) TestGetApiKeyType() { keyName := "workspaceKey" require := s.Require() - apiKey, err := s.apiKeyService.Generate(apikey.ApiKeyTypeWorkspace, keyName) + apiKey, err := s.apiKeyService.Create(context.TODO(), models.ApiKeyTypeWorkspace, keyName) require.Nil(err) - res := s.apiKeyService.IsWorkspaceApiKey(apiKey) - require.True(res) -} - -func (s *ApiKeyServiceTestSuite) TestIsWorkspaceApiKey_False() { - keyName := "clientKey" - - require := s.Require() - - apiKey, err := s.apiKeyService.Generate(apikey.ApiKeyTypeClient, keyName) + apiKeyType, err := s.apiKeyService.GetApiKeyType(context.TODO(), apiKey) require.Nil(err) - - res := s.apiKeyService.IsWorkspaceApiKey(apiKey) - require.False(res) + require.Equal(models.ApiKeyTypeWorkspace, apiKeyType) } diff --git a/pkg/server/builds/create.go b/pkg/server/builds/create.go new file mode 100644 index 0000000000..9b4986a6a0 --- /dev/null +++ b/pkg/server/builds/create.go @@ -0,0 +1,88 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package builds + +import ( + "context" + + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/services" + "github.com/daytonaio/daytona/pkg/telemetry" + "github.com/docker/docker/pkg/stringid" + + log "github.com/sirupsen/logrus" +) + +func (s *BuildService) Create(ctx context.Context, b services.CreateBuildDTO) (string, error) { + ctx, err := s.buildStore.BeginTransaction(ctx) + if err != nil { + return "", s.handleCreateError(ctx, nil, err) + } + + id := stringid.GenerateRandomID() + id = stringid.TruncateID(id) + + workspaceTemplate, err := s.findWorkspaceTemplate(ctx, b.WorkspaceTemplateName) + if err != nil { + return "", s.handleCreateError(ctx, nil, err) + } + + repo, err := s.getRepositoryContext(ctx, workspaceTemplate.RepositoryUrl, b.Branch) + if err != nil { + return "", s.handleCreateError(ctx, nil, err) + } + + newBuild := models.Build{ + Id: id, + ContainerConfig: models.ContainerConfig{ + Image: workspaceTemplate.Image, + User: workspaceTemplate.User, + }, + BuildConfig: workspaceTemplate.BuildConfig, + Repository: repo, + EnvVars: b.EnvVars, + } + + if b.PrebuildId != nil { + newBuild.PrebuildId = b.PrebuildId + } + + err = s.buildStore.Save(ctx, &newBuild) + if err != nil { + return "", s.handleCreateError(ctx, nil, err) + } + + err = s.createJob(ctx, id, models.JobActionRun) + if err != nil { + return "", s.handleCreateError(ctx, &newBuild, err) + } + + err = s.buildStore.CommitTransaction(ctx) + return id, s.handleCreateError(ctx, &newBuild, err) +} + +func (s *BuildService) handleCreateError(ctx context.Context, b *models.Build, err error) error { + if err != nil { + err = s.buildStore.RollbackTransaction(ctx, err) + } + + if !telemetry.TelemetryEnabled(ctx) { + return err + } + + clientId := telemetry.ClientId(ctx) + + eventName := telemetry.BuildEventLifecycleCreated + if err != nil { + eventName = telemetry.BuildEventLifecycleCreationFailed + } + event := telemetry.NewBuildEvent(eventName, b, err, nil) + + telemetryError := s.trackTelemetryEvent(event, clientId) + if telemetryError != nil { + log.Trace(telemetryError) + } + + return err +} diff --git a/pkg/server/builds/dto/builds.go b/pkg/server/builds/dto/builds.go deleted file mode 100644 index 82c9c7311b..0000000000 --- a/pkg/server/builds/dto/builds.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package dto - -import ( - "github.com/daytonaio/daytona/pkg/gitprovider" - "github.com/daytonaio/daytona/pkg/workspace/project/buildconfig" -) - -type BuildCreationData struct { - Image string `json:"image" validate:"required"` - User string `json:"user" validate:"required"` - BuildConfig *buildconfig.BuildConfig `json:"buildConfig" validate:"optional"` - Repository *gitprovider.GitRepository `json:"repository" validate:"optional"` - EnvVars map[string]string `json:"envVars" validate:"required"` - PrebuildId string `json:"prebuildId" validate:"required"` -} // @name BuildCreationData diff --git a/pkg/server/builds/service.go b/pkg/server/builds/service.go index 1681ec6386..e632c58357 100644 --- a/pkg/server/builds/service.go +++ b/pkg/server/builds/service.go @@ -4,128 +4,180 @@ package builds import ( - "errors" + "context" "io" - "time" - "github.com/daytonaio/daytona/pkg/build" + "github.com/daytonaio/daytona/pkg/gitprovider" "github.com/daytonaio/daytona/pkg/logs" - "github.com/daytonaio/daytona/pkg/server/builds/dto" - "github.com/daytonaio/daytona/pkg/workspace/project/containerconfig" - "github.com/docker/docker/pkg/stringid" -) + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/services" + "github.com/daytonaio/daytona/pkg/stores" + "github.com/daytonaio/daytona/pkg/telemetry" -type IBuildService interface { - Create(dto.BuildCreationData) (string, error) - Find(filter *build.Filter) (*build.Build, error) - List(filter *build.Filter) ([]*build.Build, error) - MarkForDeletion(filter *build.Filter, force bool) []error - Delete(id string) error - AwaitEmptyList(time.Duration) error - GetBuildLogReader(buildId string) (io.Reader, error) -} + log "github.com/sirupsen/logrus" +) type BuildServiceConfig struct { - BuildStore build.Store - LoggerFactory logs.LoggerFactory + BuildStore stores.BuildStore + FindWorkspaceTemplate func(ctx context.Context, name string) (*models.WorkspaceTemplate, error) + GetRepositoryContext func(ctx context.Context, url, branch string) (*gitprovider.GitRepository, error) + CreateJob func(ctx context.Context, buildId string, action models.JobAction) error + TrackTelemetryEvent func(event telemetry.Event, clientId string) error + LoggerFactory logs.ILoggerFactory } type BuildService struct { - buildStore build.Store - loggerFactory logs.LoggerFactory + buildStore stores.BuildStore + findWorkspaceTemplate func(ctx context.Context, name string) (*models.WorkspaceTemplate, error) + getRepositoryContext func(ctx context.Context, url, branch string) (*gitprovider.GitRepository, error) + createJob func(ctx context.Context, buildId string, action models.JobAction) error + trackTelemetryEvent func(event telemetry.Event, clientId string) error + loggerFactory logs.ILoggerFactory } -func NewBuildService(config BuildServiceConfig) IBuildService { +func NewBuildService(config BuildServiceConfig) services.IBuildService { return &BuildService{ - buildStore: config.BuildStore, - loggerFactory: config.LoggerFactory, + buildStore: config.BuildStore, + findWorkspaceTemplate: config.FindWorkspaceTemplate, + getRepositoryContext: config.GetRepositoryContext, + loggerFactory: config.LoggerFactory, + createJob: config.CreateJob, + trackTelemetryEvent: config.TrackTelemetryEvent, } } -func (s *BuildService) Create(b dto.BuildCreationData) (string, error) { - var newBuild build.Build +func (s *BuildService) Find(ctx context.Context, filter *services.BuildFilter) (*services.BuildDTO, error) { + var storeFilter *stores.BuildFilter - id := stringid.GenerateRandomID() - id = stringid.TruncateID(id) - - newBuild.Id = id - newBuild.State = build.BuildStatePendingRun - newBuild.ContainerConfig = containerconfig.ContainerConfig{ - Image: b.Image, - User: b.User, + if filter != nil { + storeFilter = &filter.StoreFilter } - newBuild.BuildConfig = b.BuildConfig - newBuild.Repository = b.Repository - newBuild.EnvVars = b.EnvVars - newBuild.PrebuildId = b.PrebuildId - err := s.buildStore.Save(&newBuild) + build, err := s.buildStore.Find(ctx, storeFilter) if err != nil { - return "", err + return nil, err + } + + state := build.GetState() + + if state.Name == models.ResourceStateNameDeleted && (filter == nil || !filter.ShowDeleted) { + return nil, services.ErrBuildDeleted } - return id, nil + return &services.BuildDTO{ + Build: *build, + State: state, + }, nil } -func (s *BuildService) Find(filter *build.Filter) (*build.Build, error) { - return s.buildStore.Find(filter) +func (s *BuildService) List(ctx context.Context, filter *services.BuildFilter) ([]*services.BuildDTO, error) { + var storeFilter *stores.BuildFilter + + if filter != nil { + storeFilter = &filter.StoreFilter + } + + builds, err := s.buildStore.List(ctx, storeFilter) + if err != nil { + return nil, err + } + + var result []*services.BuildDTO + + for _, b := range builds { + state := b.GetState() + + if state.Name == models.ResourceStateNameDeleted && (filter == nil || !filter.ShowDeleted) { + continue + } + + result = append(result, &services.BuildDTO{ + Build: *b, + State: state, + }) + } + + return result, nil } -func (s *BuildService) List(filter *build.Filter) ([]*build.Build, error) { - return s.buildStore.List(filter) +func (s *BuildService) HandleSuccessfulRemoval(ctx context.Context, id string) error { + return s.buildStore.Delete(ctx, id) } -func (s *BuildService) MarkForDeletion(filter *build.Filter, force bool) []error { +func (s *BuildService) Delete(ctx context.Context, filter *services.BuildFilter, force bool) []error { var errors []error - builds, err := s.List(filter) + builds, err := s.List(ctx, filter) if err != nil { - return []error{err} + return []error{s.handleDeleteError(ctx, nil, err, force)} } for _, b := range builds { if force { - b.State = build.BuildStatePendingForcedDelete + err = s.createJob(ctx, b.Id, models.JobActionForceDelete) + err = s.handleDeleteError(ctx, &b.Build, err, force) + if err != nil { + errors = append(errors, err) + } } else { - b.State = build.BuildStatePendingDelete - } - - err = s.buildStore.Save(b) - if err != nil { - errors = append(errors, err) + err = s.createJob(ctx, b.Id, models.JobActionDelete) + err = s.handleDeleteError(ctx, &b.Build, err, force) + if err != nil { + errors = append(errors, err) + } } } return errors } -func (s *BuildService) Delete(id string) error { - return s.buildStore.Delete(id) -} +func (s *BuildService) handleDeleteError(ctx context.Context, b *models.Build, err error, force bool) error { + if !telemetry.TelemetryEnabled(ctx) { + return err + } -func (s *BuildService) AwaitEmptyList(waitTime time.Duration) error { - timeout := time.NewTimer(waitTime) - defer timeout.Stop() + clientId := telemetry.ClientId(ctx) - for { - select { - case <-timeout.C: - return errors.New("awaiting empty build list timed out") - default: - builds, err := s.List(nil) - if err != nil { - return err - } + eventName := telemetry.BuildEventLifecycleDeleted + if force { + eventName = telemetry.BuildEventLifecycleForceDeleted + } + if err != nil { + eventName = telemetry.BuildEventLifecycleDeletionFailed + if force { + eventName = telemetry.BuildEventLifecycleForceDeletionFailed + } + } - if len(builds) == 0 { - return nil - } + event := telemetry.NewBuildEvent(eventName, b, err, nil) - time.Sleep(time.Second) - } + telemetryError := s.trackTelemetryEvent(event, clientId) + if telemetryError != nil { + log.Trace(telemetryError) } + + return err +} + +func (s *BuildService) UpdateLastJob(ctx context.Context, buildId, jobId string) error { + b, err := s.buildStore.Find(ctx, &stores.BuildFilter{ + Id: &buildId, + }) + if err != nil { + return err + } + + b.LastJobId = &jobId + // Make sure the old relation doesn't get saved to the store + b.LastJob = nil + + return s.buildStore.Save(ctx, b) +} + +func (s *BuildService) GetBuildLogReader(ctx context.Context, buildId string) (io.Reader, error) { + return s.loggerFactory.CreateLogReader(buildId) } -func (s *BuildService) GetBuildLogReader(buildId string) (io.Reader, error) { - return s.loggerFactory.CreateBuildLogReader(buildId) +func (s *BuildService) GetBuildLogWriter(ctx context.Context, buildId string) (io.WriteCloser, error) { + return s.loggerFactory.CreateLogWriter(buildId) } diff --git a/pkg/server/builds/service_test.go b/pkg/server/builds/service_test.go index 4124b85613..2e88819a7c 100644 --- a/pkg/server/builds/service_test.go +++ b/pkg/server/builds/service_test.go @@ -4,37 +4,38 @@ package builds_test import ( + "context" "testing" build_internal "github.com/daytonaio/daytona/internal/testing/build" - "github.com/daytonaio/daytona/pkg/build" + "github.com/daytonaio/daytona/internal/testing/job" "github.com/daytonaio/daytona/pkg/gitprovider" + "github.com/daytonaio/daytona/pkg/models" "github.com/daytonaio/daytona/pkg/server/builds" - "github.com/daytonaio/daytona/pkg/server/builds/dto" - "github.com/daytonaio/daytona/pkg/workspace/project/buildconfig" - "github.com/daytonaio/daytona/pkg/workspace/project/containerconfig" + "github.com/daytonaio/daytona/pkg/services" + "github.com/daytonaio/daytona/pkg/stores" + "github.com/daytonaio/daytona/pkg/telemetry" "github.com/stretchr/testify/suite" ) var build1Image = "image1" var build1User = "user1" -var build1 *build.Build = &build.Build{ +var build1 *models.Build = &models.Build{ Id: "id1", - ContainerConfig: containerconfig.ContainerConfig{ + ContainerConfig: models.ContainerConfig{ Image: build1Image, User: build1User, }, - BuildConfig: &buildconfig.BuildConfig{}, + BuildConfig: &models.BuildConfig{}, Repository: &gitprovider.GitRepository{ Sha: "sha1", }, - State: build.BuildStatePublished, } -var build2 *build.Build = &build.Build{ +var build2 *models.Build = &models.Build{ Id: "id2", - ContainerConfig: containerconfig.ContainerConfig{ + ContainerConfig: models.ContainerConfig{ Image: "image2", User: "user2", }, @@ -42,12 +43,11 @@ var build2 *build.Build = &build.Build{ Repository: &gitprovider.GitRepository{ Sha: "sha2", }, - State: build.BuildStatePublished, } -var build3 *build.Build = &build.Build{ +var build3 *models.Build = &models.Build{ Id: "id3", - ContainerConfig: containerconfig.ContainerConfig{ + ContainerConfig: models.ContainerConfig{ Image: "image3", User: "user3", }, @@ -55,12 +55,11 @@ var build3 *build.Build = &build.Build{ Repository: &gitprovider.GitRepository{ Sha: "sha3", }, - State: build.BuildStatePendingRun, } -var build4 *build.Build = &build.Build{ +var build4 *models.Build = &models.Build{ Id: "id4", - ContainerConfig: containerconfig.ContainerConfig{ + ContainerConfig: models.ContainerConfig{ Image: "image4", User: "user4", }, @@ -68,19 +67,26 @@ var build4 *build.Build = &build.Build{ Repository: &gitprovider.GitRepository{ Sha: "sha4", }, - State: build.BuildStatePendingRun, } -var expectedBuilds []*build.Build -var expectedFilteredBuilds []*build.Build +var workspaceTemplate = &models.WorkspaceTemplate{ + Name: "workspaceTemplateName", + RepositoryUrl: "repositoryUrl", + Image: "image", + User: "user", + BuildConfig: &models.BuildConfig{}, +} + +var expectedBuilds []*models.Build +var expectedFilteredBuilds []*models.Build -var expectedBuildsMap map[string]*build.Build -var expectedFilteredBuildsMap map[string]*build.Build +var expectedBuildsMap map[string]*models.Build +var expectedFilteredBuildsMap map[string]*models.Build type BuildServiceTestSuite struct { suite.Suite - buildService builds.IBuildService - buildStore build.Store + buildService services.IBuildService + buildStore stores.BuildStore } func NewBuildServiceTestSuite() *BuildServiceTestSuite { @@ -88,32 +94,55 @@ func NewBuildServiceTestSuite() *BuildServiceTestSuite { } func (s *BuildServiceTestSuite) SetupTest() { - expectedBuilds = []*build.Build{ + expectedBuilds = []*models.Build{ build1, build2, build3, } - expectedBuildsMap = map[string]*build.Build{ + expectedBuildsMap = map[string]*models.Build{ build1.Id: build1, build2.Id: build2, build3.Id: build3, } - expectedFilteredBuilds = []*build.Build{ + expectedFilteredBuilds = []*models.Build{ build1, build2, } - expectedFilteredBuildsMap = map[string]*build.Build{ + expectedFilteredBuildsMap = map[string]*models.Build{ build1.Id: build1, build2.Id: build2, } - s.buildStore = build_internal.NewInMemoryBuildStore() + jobStore := job.NewInMemoryJobStore() + + s.buildStore = build_internal.NewInMemoryBuildStore(jobStore) s.buildService = builds.NewBuildService(builds.BuildServiceConfig{ BuildStore: s.buildStore, + TrackTelemetryEvent: func(event telemetry.Event, clientId string) error { + return nil + }, + FindWorkspaceTemplate: func(ctx context.Context, name string) (*models.WorkspaceTemplate, error) { + return workspaceTemplate, nil + }, + GetRepositoryContext: func(ctx context.Context, url, branch string) (*gitprovider.GitRepository, error) { + return &gitprovider.GitRepository{ + Url: url, + Branch: branch, + }, nil + }, + CreateJob: func(ctx context.Context, buildId string, action models.JobAction) error { + return jobStore.Save(ctx, &models.Job{ + Id: buildId, + ResourceId: buildId, + ResourceType: models.ResourceTypeRunner, + Action: action, + State: models.JobStateSuccess, + }) + }, }) for _, b := range expectedBuilds { - _ = s.buildStore.Save(b) + _ = s.buildStore.Save(context.TODO(), b) } } @@ -124,19 +153,21 @@ func TestBuildService(t *testing.T) { func (s *BuildServiceTestSuite) TestList() { require := s.Require() - builds, err := s.buildService.List(nil) + builds, err := s.buildService.List(context.TODO(), nil) require.Nil(err) - require.ElementsMatch(expectedBuilds, builds) + require.Len(builds, len(expectedBuilds)) } func (s *BuildServiceTestSuite) TestFind() { require := s.Require() - build, err := s.buildService.Find(&build.Filter{ - Id: &build1.Id, + build, err := s.buildService.Find(context.TODO(), &services.BuildFilter{ + StoreFilter: stores.BuildFilter{ + Id: &build1.Id, + }, }) require.Nil(err) - require.Equal(build1, build) + require.Equal(build1.Id, build.Id) } func (s *BuildServiceTestSuite) TestSave() { @@ -144,49 +175,41 @@ func (s *BuildServiceTestSuite) TestSave() { require := s.Require() - createBuildDto := dto.BuildCreationData{ - Image: build4.ContainerConfig.Image, - User: build4.ContainerConfig.User, - BuildConfig: build4.BuildConfig, - Repository: build4.Repository, - EnvVars: build4.EnvVars, - PrebuildId: build4.PrebuildId, + createBuildDto := services.CreateBuildDTO{ + WorkspaceTemplateName: workspaceTemplate.Name, + Branch: "branch", + PrebuildId: build4.PrebuildId, + EnvVars: build4.EnvVars, } - _, err := s.buildService.Create(createBuildDto) + _, err := s.buildService.Create(context.TODO(), createBuildDto) require.Nil(err) - _, err = s.buildService.List(nil) + _, err = s.buildService.List(context.TODO(), nil) require.Nil(err) require.Contains(expectedBuilds, build4) } -func (s *BuildServiceTestSuite) TestMarkForDeletion() { +func (s *BuildServiceTestSuite) TestDelete() { expectedBuilds = append(expectedBuilds, build3) require := s.Require() - err := s.buildService.MarkForDeletion(&build.Filter{ - Id: &build3.Id, + err := s.buildService.Delete(context.TODO(), &services.BuildFilter{ + StoreFilter: stores.BuildFilter{ + Id: &build3.Id, + }, }, false) require.Nil(err) - - b, errs := s.buildService.Find(&build.Filter{ - Id: &build3.Id, - }) - require.Nil(errs) - require.Equal(b.State, build.BuildStatePendingDelete) } -func (s *BuildServiceTestSuite) TestDelete() { - expectedBuilds = expectedBuilds[:2] - +func (s *BuildServiceTestSuite) TestHandleSuccessfulRemoval() { require := s.Require() - err := s.buildService.Delete(build3.Id) + err := s.buildService.HandleSuccessfulRemoval(context.TODO(), build3.Id) require.Nil(err) - builds, err := s.buildService.List(nil) + builds, err := s.buildService.List(context.TODO(), nil) require.Nil(err) - require.ElementsMatch(expectedBuilds, builds) + require.NotContains(builds, build3) } diff --git a/pkg/server/config.go b/pkg/server/config.go index c72227d1b8..aaaf7cbfe7 100644 --- a/pkg/server/config.go +++ b/pkg/server/config.go @@ -10,7 +10,10 @@ import ( "path/filepath" "github.com/daytonaio/daytona/cmd/daytona/config" + "github.com/daytonaio/daytona/internal/util" + "github.com/daytonaio/daytona/pkg/logs" "github.com/google/uuid" + log "github.com/sirupsen/logrus" ) func GetConfig() (*Config, error) { @@ -54,7 +57,12 @@ func GetConfig() (*Config, error) { } if c.LogFile == nil { - c.LogFile = getDefaultLogFileConfig() + logFilePath, err := getDefaultLogFilePath() + if err != nil { + log.Error("failed to get default log file path") + } + + c.LogFile = logs.GetDefaultLogFileConfig(logFilePath) } err = Save(c) @@ -75,10 +83,7 @@ func configFilePath() (string, error) { } func Save(c Config) error { - if err := directoryValidator(&c.BinariesPath); err != nil { - return err - } - if err := directoryValidator(&c.ProvidersDir); err != nil { + if err := util.DirectoryValidator(&c.BinariesPath); err != nil { return err } @@ -114,14 +119,18 @@ func GetConfigDir() (string, error) { return filepath.Join(configDir, "server"), nil } -func GetWorkspaceLogsDir(configDir string) (string, error) { - return filepath.Join(configDir, "logs"), nil +func GetTargetLogsDir(configDir string) string { + return filepath.Join(configDir, "logs", "targets") } -func directoryValidator(path *string) error { - _, err := os.Stat(*path) - if os.IsNotExist(err) { - return os.MkdirAll(*path, 0700) - } - return err +func GetRunnerLogsDir(configDir string) string { + return filepath.Join(configDir, "logs", "runners") +} + +func GetWorkspaceLogsDir(configDir string) string { + return filepath.Join(configDir, "logs", "workspaces") +} + +func GetBuildLogsDir(configDir string) string { + return filepath.Join(configDir, "logs", "builds") } diff --git a/pkg/server/containerregistries/service.go b/pkg/server/containerregistries/service.go deleted file mode 100644 index cac16963e7..0000000000 --- a/pkg/server/containerregistries/service.go +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package containerregistries - -import ( - "strings" - - "github.com/daytonaio/daytona/pkg/containerregistry" -) - -type IContainerRegistryService interface { - Delete(server string) error - Find(server string) (*containerregistry.ContainerRegistry, error) - FindByImageName(imageName string) (*containerregistry.ContainerRegistry, error) - List() ([]*containerregistry.ContainerRegistry, error) - Map() (map[string]*containerregistry.ContainerRegistry, error) - Save(cr *containerregistry.ContainerRegistry) error -} - -type ContainerRegistryServiceConfig struct { - Store containerregistry.Store -} - -type ContainerRegistryService struct { - store containerregistry.Store -} - -func NewContainerRegistryService(config ContainerRegistryServiceConfig) IContainerRegistryService { - return &ContainerRegistryService{ - store: config.Store, - } -} - -func (s *ContainerRegistryService) List() ([]*containerregistry.ContainerRegistry, error) { - return s.store.List() -} - -func (s *ContainerRegistryService) Map() (map[string]*containerregistry.ContainerRegistry, error) { - list, err := s.store.List() - if err != nil { - return nil, err - } - - crs := make(map[string]*containerregistry.ContainerRegistry) - for _, cr := range list { - crs[cr.Server] = cr - } - - return crs, nil -} - -func (s *ContainerRegistryService) Find(server string) (*containerregistry.ContainerRegistry, error) { - return s.store.Find(server) -} - -func (s *ContainerRegistryService) FindByImageName(imageName string) (*containerregistry.ContainerRegistry, error) { - server := getImageServer(imageName) - - return s.Find(server) -} - -func (s *ContainerRegistryService) Save(cr *containerregistry.ContainerRegistry) error { - return s.store.Save(cr) -} - -func (s *ContainerRegistryService) Delete(server string) error { - cr, err := s.Find(server) - if err != nil { - return err - } - return s.store.Delete(cr) -} - -func getImageServer(imageName string) string { - parts := strings.Split(imageName, "/") - - if len(parts) < 3 { - return "docker.io" - } - - return parts[0] -} diff --git a/pkg/server/containerregistries/service_test.go b/pkg/server/containerregistries/service_test.go deleted file mode 100644 index 800fbdc12e..0000000000 --- a/pkg/server/containerregistries/service_test.go +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package containerregistries_test - -import ( - "testing" - - t_containerregistries "github.com/daytonaio/daytona/internal/testing/server/containerregistries" - "github.com/daytonaio/daytona/pkg/containerregistry" - "github.com/daytonaio/daytona/pkg/server/containerregistries" - "github.com/stretchr/testify/require" -) - -func TestContainerRegistryService(t *testing.T) { - crStore := t_containerregistries.NewInMemoryContainerRegistryStore() - - service := containerregistries.NewContainerRegistryService(containerregistries.ContainerRegistryServiceConfig{ - Store: crStore, - }) - - t.Run("CreateContainerRegistry", func(t *testing.T) { - var crOrg = &containerregistry.ContainerRegistry{ - Server: "example.com", - Username: "user", - Password: "password", - } - - err := service.Save(crOrg) - - require.Nil(t, err) - - cr, err := service.Find("example.com") - - require.Nil(t, err) - require.EqualValues(t, crOrg, cr) - }) - - t.Run("FindByImageName", func(t *testing.T) { - var crOrg = &containerregistry.ContainerRegistry{ - Server: "example.com", - Username: "user", - Password: "password", - } - - err := service.Save(crOrg) - - require.Nil(t, err) - - cr, err := service.FindByImageName("example.com/image/image") - - require.Nil(t, err) - require.EqualValues(t, crOrg, cr) - }) -} diff --git a/pkg/server/defaults.go b/pkg/server/defaults.go index 03b94bcfe1..4d6a76b15c 100644 --- a/pkg/server/defaults.go +++ b/pkg/server/defaults.go @@ -11,7 +11,8 @@ import ( "path/filepath" "strconv" - "github.com/daytonaio/daytona/cmd/daytona/config" + "github.com/daytonaio/daytona/internal/util" + "github.com/daytonaio/daytona/pkg/logs" "github.com/google/uuid" log "github.com/sirupsen/logrus" @@ -23,22 +24,14 @@ const defaultSamplesIndexUrl = "https://raw.githubusercontent.com/daytonaio/dayt const defaultHeadscalePort = 3987 const defaultApiPort = 3986 const defaultBuilderImage = "daytonaio/workspace-project:latest" -const defaultProjectImage = "daytonaio/workspace-project:latest" -const defaultProjectUser = "daytona" +const defaultWorkspaceImage = "daytonaio/workspace-project:latest" +const defaultWorkspaceUser = "daytona" const defaultLocalBuilderRegistryPort = 3988 const defaultLocalBuilderRegistryImage = "registry:2.8.3" const defaultBuilderRegistryServer = "local" const defaultBuildImageNamespace = "" -var defaultLogFileConfig = LogFileConfig{ - MaxSize: 100, // megabytes - MaxBackups: 7, - MaxAge: 15, // days - LocalTime: true, - Compress: true, -} - var us_defaultFrpsConfig = FRPSConfig{ Domain: "try-us.daytona.app", Port: 7000, @@ -94,100 +87,32 @@ func getDefaultFRPSConfig() *FRPSConfig { } } -func getDefaultLogFileConfig() *LogFileConfig { - logFilePath, err := getDefaultLogFilePath() - if err != nil { - log.Error("failed to get default log file path") - } - - logFileConfig := LogFileConfig{ - Path: logFilePath, - MaxSize: defaultLogFileConfig.MaxSize, - MaxBackups: defaultLogFileConfig.MaxBackups, - MaxAge: defaultLogFileConfig.MaxAge, - LocalTime: defaultLogFileConfig.LocalTime, - Compress: defaultLogFileConfig.Compress, - } - - logFileMaxSize := os.Getenv("DEFAULT_LOG_FILE_MAX_SIZE") - if logFileMaxSize != "" { - value, err := strconv.Atoi(logFileMaxSize) - if err != nil { - log.Error(fmt.Printf("%s. Using default log file max size.", err)) - } else { - logFileConfig.MaxSize = value - } - } - - logFileMaxBackups := os.Getenv("DEFAULT_LOG_FILE_MAX_BACKUPS") - if logFileMaxBackups != "" { - value, err := strconv.Atoi(logFileMaxBackups) - if err != nil { - log.Error(fmt.Printf("%s. Using default log file max backups.", err)) - } else { - logFileConfig.MaxBackups = value - } - } - - logFileMaxAge := os.Getenv("DEFAULT_LOG_FILE_MAX_AGE") - if logFileMaxAge != "" { - value, err := strconv.Atoi(logFileMaxAge) - if err != nil { - log.Error(fmt.Printf("%s. Using default log file max age.", err)) - } else { - logFileConfig.MaxAge = value - } - } - - logFileLocalTime := os.Getenv("DEFAULT_LOG_FILE_LOCAL_TIME") - if logFileLocalTime != "" { - value, err := strconv.ParseBool(logFileLocalTime) - if err != nil { - log.Error(fmt.Printf("%s. Using default log file local time.", err)) - } else { - logFileConfig.LocalTime = value - } - } - - logFileCompress := os.Getenv("DEFAULT_LOG_FILE_COMPRESS") - if logFileCompress != "" { - value, err := strconv.ParseBool(logFileCompress) - if err != nil { - log.Error(fmt.Printf("%s. Using default log file compress.", err)) - } else { - logFileConfig.Compress = value - } - } - - return &logFileConfig -} - func getDefaultConfig() (*Config, error) { - providersDir, err := getDefaultProvidersDir() + binariesPath, err := getDefaultBinariesPath() if err != nil { - return nil, errors.New("failed to get default providers dir") + return nil, errors.New("failed to get default binaries path") } - binariesPath, err := getDefaultBinariesPath() + logFilePath, err := getDefaultLogFilePath() if err != nil { - return nil, errors.New("failed to get default binaries path") + log.Error("failed to get default log file path") } c := Config{ Id: uuid.NewString(), RegistryUrl: defaultRegistryUrl, - ProvidersDir: providersDir, ServerDownloadUrl: defaultServerDownloadUrl, ApiPort: defaultApiPort, HeadscalePort: defaultHeadscalePort, BinariesPath: binariesPath, Frps: getDefaultFRPSConfig(), - LogFile: getDefaultLogFileConfig(), - DefaultProjectImage: defaultProjectImage, - DefaultProjectUser: defaultProjectUser, + LogFile: logs.GetDefaultLogFileConfig(logFilePath), + DefaultWorkspaceImage: defaultWorkspaceImage, + DefaultWorkspaceUser: defaultWorkspaceUser, BuilderImage: defaultBuilderImage, LocalBuilderRegistryPort: defaultLocalBuilderRegistryPort, LocalBuilderRegistryImage: defaultLocalBuilderRegistryImage, + LocalRunnerDisabled: util.Pointer(false), BuilderRegistryServer: defaultBuilderRegistryServer, BuildImageNamespace: defaultBuildImageNamespace, SamplesIndexUrl: defaultSamplesIndexUrl, @@ -199,9 +124,6 @@ func getDefaultConfig() (*Config, error) { if os.Getenv("DEFAULT_SERVER_DOWNLOAD_URL") != "" { c.ServerDownloadUrl = os.Getenv("DEFAULT_SERVER_DOWNLOAD_URL") } - if os.Getenv("DEFAULT_PROVIDERS_DIR") != "" { - c.ProvidersDir = os.Getenv("DEFAULT_PROVIDERS_DIR") - } if os.Getenv("DEFAULT_BINARIES_PATH") != "" { c.BinariesPath = os.Getenv("DEFAULT_BINARIES_PATH") } @@ -237,15 +159,6 @@ func parsePort(port string) (uint32, error) { return uint32(p), nil } -func getDefaultProvidersDir() (string, error) { - configDir, err := config.GetConfigDir() - if err != nil { - return "", err - } - - return filepath.Join(configDir, "providers"), nil -} - func getDefaultLogFilePath() (string, error) { configDir, err := GetConfigDir() if err != nil { diff --git a/pkg/server/env/service.go b/pkg/server/env/service.go new file mode 100644 index 0000000000..c7268e7d01 --- /dev/null +++ b/pkg/server/env/service.go @@ -0,0 +1,52 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package env + +import ( + "context" + + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/services" + "github.com/daytonaio/daytona/pkg/stores" +) + +type EnvironmentVariableServiceConfig struct { + EnvironmentVariableStore stores.EnvironmentVariableStore +} + +func NewEnvironmentVariableService(config EnvironmentVariableServiceConfig) services.IEnvironmentVariableService { + return &EnvironmentVariableService{ + environmentVariableStore: config.EnvironmentVariableStore, + } +} + +type EnvironmentVariableService struct { + environmentVariableStore stores.EnvironmentVariableStore +} + +func (s *EnvironmentVariableService) List(ctx context.Context) ([]*models.EnvironmentVariable, error) { + return s.environmentVariableStore.List(ctx) +} + +func (s *EnvironmentVariableService) Map(ctx context.Context) (services.EnvironmentVariables, error) { + envVars, err := s.List(ctx) + if err != nil { + return nil, err + } + + envVarsMap := services.EnvironmentVariables{} + for _, envVar := range envVars { + envVarsMap[envVar.Key] = envVar.Value + } + + return envVarsMap, nil +} + +func (s *EnvironmentVariableService) Save(ctx context.Context, environmentVariable *models.EnvironmentVariable) error { + return s.environmentVariableStore.Save(ctx, environmentVariable) +} + +func (s *EnvironmentVariableService) Delete(ctx context.Context, key string) error { + return s.environmentVariableStore.Delete(ctx, key) +} diff --git a/pkg/server/env/service_test.go b/pkg/server/env/service_test.go new file mode 100644 index 0000000000..d6d2f2bca8 --- /dev/null +++ b/pkg/server/env/service_test.go @@ -0,0 +1,69 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package env_test + +import ( + "context" + "testing" + + t_envvar "github.com/daytonaio/daytona/internal/testing/server/env" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/server/env" + "github.com/daytonaio/daytona/pkg/services" + "github.com/daytonaio/daytona/pkg/stores" + "github.com/stretchr/testify/suite" +) + +type EnvironmentVariableServiceTestSuite struct { + suite.Suite + environmentVariableService services.IEnvironmentVariableService + environmentVariableStore stores.EnvironmentVariableStore +} + +func NewEnvironmentVariableTestSuite() *EnvironmentVariableServiceTestSuite { + return &EnvironmentVariableServiceTestSuite{} +} + +func (s *EnvironmentVariableServiceTestSuite) SetupTest() { + s.environmentVariableStore = t_envvar.NewInMemoryEnvironmentVariableStore() + s.environmentVariableService = env.NewEnvironmentVariableService(env.EnvironmentVariableServiceConfig{ + EnvironmentVariableStore: s.environmentVariableStore, + }) +} + +func TestEnvironmentVariableService(t *testing.T) { + suite.Run(t, NewEnvironmentVariableTestSuite()) +} + +func (s *EnvironmentVariableServiceTestSuite) TestSaveEnvironmentVariable() { + envVar := &models.EnvironmentVariable{ + Key: "key1", + Value: "value1", + } + + err := s.environmentVariableService.Save(context.TODO(), envVar) + s.Require().Nil(err) + + envVars, err := s.environmentVariableStore.List(context.TODO()) + s.Require().Nil(err) + s.Require().NotNil(envVars) + s.Require().Contains(envVars, envVar) +} + +func (s *EnvironmentVariableServiceTestSuite) TestDeleteEnvironmentVariable() { + envVar := &models.EnvironmentVariable{ + Key: "key1", + Value: "value1", + } + + err := s.environmentVariableService.Save(context.TODO(), envVar) + s.Require().Nil(err) + + err = s.environmentVariableService.Delete(context.TODO(), envVar.Key) + s.Require().Nil(err) + + envVars, err := s.environmentVariableStore.List(context.TODO()) + s.Require().Nil(err) + s.Require().NotContains(envVars, envVar) +} diff --git a/pkg/server/gitproviders/branches.go b/pkg/server/gitproviders/branches.go index 186a160f57..27b5f0f2d9 100644 --- a/pkg/server/gitproviders/branches.go +++ b/pkg/server/gitproviders/branches.go @@ -4,13 +4,14 @@ package gitproviders import ( + "context" "fmt" "github.com/daytonaio/daytona/pkg/gitprovider" ) -func (s *GitProviderService) GetRepoBranches(gitProviderId, namespaceId, repositoryId string, options gitprovider.ListOptions) ([]*gitprovider.GitBranch, error) { - gitProvider, err := s.GetGitProvider(gitProviderId) +func (s *GitProviderService) GetRepoBranches(ctx context.Context, gitProviderId, namespaceId, repositoryId string, options gitprovider.ListOptions) ([]*gitprovider.GitBranch, error) { + gitProvider, err := s.GetGitProvider(ctx, gitProviderId) if err != nil { return nil, fmt.Errorf("failed to get git provider: %w", err) } diff --git a/pkg/server/gitproviders/config.go b/pkg/server/gitproviders/config.go index 0e825f344c..0b0d8d9687 100644 --- a/pkg/server/gitproviders/config.go +++ b/pkg/server/gitproviders/config.go @@ -4,25 +4,30 @@ package gitproviders import ( + "context" "net/url" "strconv" "github.com/daytonaio/daytona/pkg/gitprovider" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/telemetry" "github.com/docker/docker/pkg/stringid" + + log "github.com/sirupsen/logrus" ) -func (s *GitProviderService) GetConfig(id string) (*gitprovider.GitProviderConfig, error) { - return s.configStore.Find(id) +func (s *GitProviderService) FindConfig(ctx context.Context, id string) (*models.GitProviderConfig, error) { + return s.configStore.Find(ctx, id) } -func (s *GitProviderService) ListConfigs() ([]*gitprovider.GitProviderConfig, error) { - return s.configStore.List() +func (s *GitProviderService) ListConfigs(ctx context.Context) ([]*models.GitProviderConfig, error) { + return s.configStore.List(ctx) } -func (s *GitProviderService) ListConfigsForUrl(repoUrl string) ([]*gitprovider.GitProviderConfig, error) { - var gpcs []*gitprovider.GitProviderConfig +func (s *GitProviderService) ListConfigsForUrl(ctx context.Context, repoUrl string) ([]*models.GitProviderConfig, error) { + var gpcs []*models.GitProviderConfig - gitProviders, err := s.configStore.List() + gitProviders, err := s.configStore.List(ctx) if err != nil { return nil, err } @@ -31,7 +36,7 @@ func (s *GitProviderService) ListConfigsForUrl(repoUrl string) ([]*gitprovider.G p.Token = url.QueryEscape(p.Token) p.Username = url.QueryEscape(p.Username) - gitProvider, err := s.GetGitProvider(p.Id) + gitProvider, err := s.GetGitProvider(ctx, p.Id) if err != nil { return nil, err } @@ -50,15 +55,15 @@ func (s *GitProviderService) ListConfigsForUrl(repoUrl string) ([]*gitprovider.G return gpcs, nil } -func (s *GitProviderService) SetGitProviderConfig(providerConfig *gitprovider.GitProviderConfig) error { +func (s *GitProviderService) SaveConfig(ctx context.Context, providerConfig *models.GitProviderConfig) error { gitProvider, err := s.newGitProvider(providerConfig) if err != nil { - return err + return s.handleSetGitProviderConfigError(ctx, providerConfig, err) } userData, err := gitProvider.GetUser() if err != nil { - return err + return s.handleSetGitProviderConfigError(ctx, providerConfig, err) } providerConfig.Username = userData.Username if providerConfig.Id == "" { @@ -68,9 +73,9 @@ func (s *GitProviderService) SetGitProviderConfig(providerConfig *gitprovider.Gi } if providerConfig.Alias == "" { - gitProviderConfigs, err := s.ListConfigs() + gitProviderConfigs, err := s.ListConfigs(ctx) if err != nil { - return err + return s.handleSetGitProviderConfigError(ctx, providerConfig, err) } uniqueAlias := userData.Username @@ -89,5 +94,27 @@ func (s *GitProviderService) SetGitProviderConfig(providerConfig *gitprovider.Gi providerConfig.Alias = uniqueAlias } - return s.configStore.Save(providerConfig) + err = s.configStore.Save(ctx, providerConfig) + return s.handleSetGitProviderConfigError(ctx, providerConfig, err) +} + +func (s *GitProviderService) handleSetGitProviderConfigError(ctx context.Context, gpc *models.GitProviderConfig, err error) error { + if !telemetry.TelemetryEnabled(ctx) { + return err + } + + clientId := telemetry.ClientId(ctx) + + eventName := telemetry.GitProviderConfigEventLifecycleSaved + if err != nil { + eventName = telemetry.GitProviderConfigEventLifecycleSaveFailed + } + event := telemetry.NewGitProviderConfigEvent(eventName, gpc, err, nil) + + telemetryError := s.trackTelemetryEvent(event, clientId) + if telemetryError != nil { + log.Trace(telemetryError) + } + + return err } diff --git a/pkg/server/gitproviders/delete.go b/pkg/server/gitproviders/delete.go new file mode 100644 index 0000000000..0706fe9afc --- /dev/null +++ b/pkg/server/gitproviders/delete.go @@ -0,0 +1,48 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package gitproviders + +import ( + "context" + + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/telemetry" + log "github.com/sirupsen/logrus" +) + +func (s *GitProviderService) DeleteConfig(ctx context.Context, gitProviderId string) error { + gitProvider, err := s.configStore.Find(ctx, gitProviderId) + if err != nil { + return s.handleDeleteGitProviderConfigError(ctx, nil, err) + } + + err = s.detachWorkspaceTemplates(ctx, gitProvider.Id) + if err != nil { + return s.handleDeleteGitProviderConfigError(ctx, gitProvider, err) + } + + err = s.configStore.Delete(ctx, gitProvider) + return s.handleDeleteGitProviderConfigError(ctx, gitProvider, err) +} + +func (s *GitProviderService) handleDeleteGitProviderConfigError(ctx context.Context, gpc *models.GitProviderConfig, err error) error { + if !telemetry.TelemetryEnabled(ctx) { + return err + } + + clientId := telemetry.ClientId(ctx) + + eventName := telemetry.GitProviderConfigEventLifecycleDeleted + if err != nil { + eventName = telemetry.GitProviderConfigEventLifecycleDeletionFailed + } + event := telemetry.NewGitProviderConfigEvent(eventName, gpc, err, nil) + + telemetryError := s.trackTelemetryEvent(event, clientId) + if telemetryError != nil { + log.Trace(telemetryError) + } + + return err +} diff --git a/pkg/server/gitproviders/gitprovider.go b/pkg/server/gitproviders/gitprovider.go index 6f4356c358..99a6ef1b55 100644 --- a/pkg/server/gitproviders/gitprovider.go +++ b/pkg/server/gitproviders/gitprovider.go @@ -4,6 +4,7 @@ package gitproviders import ( + "context" "errors" "net/http" "net/url" @@ -11,10 +12,11 @@ import ( "github.com/daytonaio/daytona/cmd/daytona/config" "github.com/daytonaio/daytona/pkg/gitprovider" + "github.com/daytonaio/daytona/pkg/models" ) -func (s *GitProviderService) GetGitProviderForUrl(repoUrl string) (gitprovider.GitProvider, string, error) { - gitProviders, err := s.configStore.List() +func (s *GitProviderService) GetGitProviderForUrl(ctx context.Context, repoUrl string) (gitprovider.GitProvider, string, error) { + gitProviders, err := s.configStore.List(ctx) if err != nil { return nil, "", err } @@ -23,7 +25,7 @@ func (s *GitProviderService) GetGitProviderForUrl(repoUrl string) (gitprovider.G var eligibleProviderId string for _, p := range gitProviders { - gitProvider, err := s.GetGitProvider(p.Id) + gitProvider, err := s.GetGitProvider(ctx, p.Id) if err != nil { continue } @@ -46,7 +48,7 @@ func (s *GitProviderService) GetGitProviderForUrl(repoUrl string) (gitprovider.G } for _, p := range config.GetSupportedGitProviders() { - gitProvider, err := s.newGitProvider(&gitprovider.GitProviderConfig{ + gitProvider, err := s.newGitProvider(&models.GitProviderConfig{ ProviderId: p.Id, Id: p.Id, Username: "", @@ -65,10 +67,10 @@ func (s *GitProviderService) GetGitProviderForUrl(repoUrl string) (gitprovider.G return nil, "", errors.New("can not get public client for the URL " + repoUrl) } -func (s *GitProviderService) GetGitProviderForHttpRequest(req *http.Request) (gitprovider.GitProvider, error) { - var provider *gitprovider.GitProviderConfig +func (s *GitProviderService) GetGitProviderForHttpRequest(ctx context.Context, req *http.Request) (gitprovider.GitProvider, error) { + var provider *models.GitProviderConfig - gitProviders, err := s.configStore.List() + gitProviders, err := s.configStore.List(ctx) if err != nil { return nil, err } diff --git a/pkg/server/gitproviders/namespaces.go b/pkg/server/gitproviders/namespaces.go index 118bc8e6d7..a24ffc0ec2 100644 --- a/pkg/server/gitproviders/namespaces.go +++ b/pkg/server/gitproviders/namespaces.go @@ -4,13 +4,14 @@ package gitproviders import ( + "context" "fmt" "github.com/daytonaio/daytona/pkg/gitprovider" ) -func (s *GitProviderService) GetNamespaces(gitProviderId string, options gitprovider.ListOptions) ([]*gitprovider.GitNamespace, error) { - gitProvider, err := s.GetGitProvider(gitProviderId) +func (s *GitProviderService) GetNamespaces(ctx context.Context, gitProviderId string, options gitprovider.ListOptions) ([]*gitprovider.GitNamespace, error) { + gitProvider, err := s.GetGitProvider(ctx, gitProviderId) if err != nil { return nil, fmt.Errorf("failed to get git provider: %w", err) } diff --git a/pkg/server/gitproviders/prebuild_webhook.go b/pkg/server/gitproviders/prebuild_webhook.go index cda8a68b00..52ea051f04 100644 --- a/pkg/server/gitproviders/prebuild_webhook.go +++ b/pkg/server/gitproviders/prebuild_webhook.go @@ -4,13 +4,14 @@ package gitproviders import ( + "context" "fmt" "github.com/daytonaio/daytona/pkg/gitprovider" ) -func (s *GitProviderService) GetPrebuildWebhook(gitProviderId string, repo *gitprovider.GitRepository, endpointUrl string) (*string, error) { - gitProvider, err := s.GetGitProvider(gitProviderId) +func (s *GitProviderService) GetPrebuildWebhook(ctx context.Context, gitProviderId string, repo *gitprovider.GitRepository, endpointUrl string) (*string, error) { + gitProvider, err := s.GetGitProvider(ctx, gitProviderId) if err != nil { return nil, fmt.Errorf("failed to get git provider: %s", err.Error()) } @@ -23,8 +24,8 @@ func (s *GitProviderService) GetPrebuildWebhook(gitProviderId string, repo *gitp return id, nil } -func (s *GitProviderService) RegisterPrebuildWebhook(gitProviderId string, repo *gitprovider.GitRepository, endpointUrl string) (string, error) { - gitProvider, err := s.GetGitProvider(gitProviderId) +func (s *GitProviderService) RegisterPrebuildWebhook(ctx context.Context, gitProviderId string, repo *gitprovider.GitRepository, endpointUrl string) (string, error) { + gitProvider, err := s.GetGitProvider(ctx, gitProviderId) if err != nil { return "", fmt.Errorf("failed to get git provider: %s", err.Error()) } @@ -37,8 +38,8 @@ func (s *GitProviderService) RegisterPrebuildWebhook(gitProviderId string, repo return id, nil } -func (s *GitProviderService) UnregisterPrebuildWebhook(gitProviderId string, repo *gitprovider.GitRepository, id string) error { - gitProvider, err := s.GetGitProvider(gitProviderId) +func (s *GitProviderService) UnregisterPrebuildWebhook(ctx context.Context, gitProviderId string, repo *gitprovider.GitRepository, id string) error { + gitProvider, err := s.GetGitProvider(ctx, gitProviderId) if err != nil { return fmt.Errorf("failed to get git provider: %s", err.Error()) } diff --git a/pkg/server/gitproviders/pull_requests.go b/pkg/server/gitproviders/pull_requests.go index be351ec09e..3f0db9adfd 100644 --- a/pkg/server/gitproviders/pull_requests.go +++ b/pkg/server/gitproviders/pull_requests.go @@ -4,13 +4,14 @@ package gitproviders import ( + "context" "fmt" "github.com/daytonaio/daytona/pkg/gitprovider" ) -func (s *GitProviderService) GetRepoPRs(gitProviderId, namespaceId, repositoryId string, options gitprovider.ListOptions) ([]*gitprovider.GitPullRequest, error) { - gitProvider, err := s.GetGitProvider(gitProviderId) +func (s *GitProviderService) GetRepoPRs(ctx context.Context, gitProviderId, namespaceId, repositoryId string, options gitprovider.ListOptions) ([]*gitprovider.GitPullRequest, error) { + gitProvider, err := s.GetGitProvider(ctx, gitProviderId) if err != nil { return nil, fmt.Errorf("failed to get git provider: %w", err) } diff --git a/pkg/server/gitproviders/remove.go b/pkg/server/gitproviders/remove.go deleted file mode 100644 index 3f7b9c0a51..0000000000 --- a/pkg/server/gitproviders/remove.go +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package gitproviders - -import "github.com/daytonaio/daytona/pkg/workspace/project/config" - -func (s *GitProviderService) RemoveGitProvider(gitProviderId string) error { - gitProvider, err := s.configStore.Find(gitProviderId) - if err != nil { - return err - } - - // Check if project configs need to be updated - projectConfigs, err := s.projectConfigStore.List(&config.ProjectConfigFilter{ - GitProviderConfigId: &gitProviderId, - }) - - if err != nil { - return err - } - - for _, projectConfig := range projectConfigs { - projectConfig.GitProviderConfigId = nil - err = s.projectConfigStore.Save(projectConfig) - if err != nil { - return err - } - } - - return s.configStore.Delete(gitProvider) -} diff --git a/pkg/server/gitproviders/repositories.go b/pkg/server/gitproviders/repositories.go index bd9fce0896..047c71f9f4 100644 --- a/pkg/server/gitproviders/repositories.go +++ b/pkg/server/gitproviders/repositories.go @@ -4,13 +4,14 @@ package gitproviders import ( + "context" "fmt" "github.com/daytonaio/daytona/pkg/gitprovider" ) -func (s *GitProviderService) GetRepositories(gitProviderId, namespaceId string, options gitprovider.ListOptions) ([]*gitprovider.GitRepository, error) { - gitProvider, err := s.GetGitProvider(gitProviderId) +func (s *GitProviderService) GetRepositories(ctx context.Context, gitProviderId, namespaceId string, options gitprovider.ListOptions) ([]*gitprovider.GitRepository, error) { + gitProvider, err := s.GetGitProvider(ctx, gitProviderId) if err != nil { return nil, fmt.Errorf("failed to get git provider: %w", err) } diff --git a/pkg/server/gitproviders/service.go b/pkg/server/gitproviders/service.go index 8a48c13c0b..2abba7a6e0 100644 --- a/pkg/server/gitproviders/service.go +++ b/pkg/server/gitproviders/service.go @@ -4,65 +4,47 @@ package gitproviders import ( + "context" "errors" "fmt" - "net/http" "strings" "github.com/daytonaio/daytona/pkg/gitprovider" - "github.com/daytonaio/daytona/pkg/workspace/project/config" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/services" + "github.com/daytonaio/daytona/pkg/stores" + "github.com/daytonaio/daytona/pkg/telemetry" ) -type IGitProviderService interface { - GetConfig(id string) (*gitprovider.GitProviderConfig, error) - ListConfigsForUrl(url string) ([]*gitprovider.GitProviderConfig, error) - GetGitProvider(id string) (gitprovider.GitProvider, error) - GetGitProviderForUrl(url string) (gitprovider.GitProvider, string, error) - GetGitProviderForHttpRequest(req *http.Request) (gitprovider.GitProvider, error) - GetGitUser(gitProviderId string) (*gitprovider.GitUser, error) - GetNamespaces(gitProviderId string, options gitprovider.ListOptions) ([]*gitprovider.GitNamespace, error) - GetRepoBranches(gitProviderId string, namespaceId string, repositoryId string, options gitprovider.ListOptions) ([]*gitprovider.GitBranch, error) - GetRepoPRs(gitProviderId string, namespaceId string, repositoryId string, options gitprovider.ListOptions) ([]*gitprovider.GitPullRequest, error) - GetRepositories(gitProviderId string, namespaceId string, options gitprovider.ListOptions) ([]*gitprovider.GitRepository, error) - ListConfigs() ([]*gitprovider.GitProviderConfig, error) - RemoveGitProvider(gitProviderId string) error - SetGitProviderConfig(providerConfig *gitprovider.GitProviderConfig) error - GetLastCommitSha(repo *gitprovider.GitRepository) (string, error) - RegisterPrebuildWebhook(gitProviderId string, repo *gitprovider.GitRepository, endpointUrl string) (string, error) - GetPrebuildWebhook(gitProviderId string, repo *gitprovider.GitRepository, endpointUrl string) (*string, error) - UnregisterPrebuildWebhook(gitProviderId string, repo *gitprovider.GitRepository, id string) error -} - -type ProjectConfigStore interface { - Save(projectConfig *config.ProjectConfig) error - List(filter *config.ProjectConfigFilter) ([]*config.ProjectConfig, error) -} - type GitProviderServiceConfig struct { - ConfigStore gitprovider.ConfigStore - ProjectConfigStore ProjectConfigStore + ConfigStore stores.GitProviderConfigStore + + DetachWorkspaceTemplates func(ctx context.Context, gitProviderConfigId string) error + TrackTelemetryEvent func(event telemetry.Event, clientId string) error } type GitProviderService struct { - configStore gitprovider.ConfigStore - projectConfigStore ProjectConfigStore + configStore stores.GitProviderConfigStore + detachWorkspaceTemplates func(ctx context.Context, gitProviderConfigId string) error + trackTelemetryEvent func(event telemetry.Event, clientId string) error } -func NewGitProviderService(config GitProviderServiceConfig) IGitProviderService { +func NewGitProviderService(config GitProviderServiceConfig) services.IGitProviderService { return &GitProviderService{ - configStore: config.ConfigStore, - projectConfigStore: config.ProjectConfigStore, + configStore: config.ConfigStore, + detachWorkspaceTemplates: config.DetachWorkspaceTemplates, + trackTelemetryEvent: config.TrackTelemetryEvent, } } var codebergUrl = "https://codeberg.org" -func (s *GitProviderService) GetGitProvider(id string) (gitprovider.GitProvider, error) { - providerConfig, err := s.configStore.Find(id) +func (s *GitProviderService) GetGitProvider(ctx context.Context, id string) (gitprovider.GitProvider, error) { + providerConfig, err := s.configStore.Find(ctx, id) if err != nil { // If config is not defined, use the default (public) client without token - if gitprovider.IsGitProviderNotFound(err) { - providerConfig = &gitprovider.GitProviderConfig{ + if stores.IsGitProviderNotFound(err) { + providerConfig = &models.GitProviderConfig{ Id: id, ProviderId: id, Username: "", @@ -77,12 +59,12 @@ func (s *GitProviderService) GetGitProvider(id string) (gitprovider.GitProvider, return s.newGitProvider(providerConfig) } -func (s *GitProviderService) GetLastCommitSha(repo *gitprovider.GitRepository) (string, error) { +func (s *GitProviderService) GetLastCommitSha(ctx context.Context, repo *gitprovider.GitRepository) (string, error) { var err error var provider gitprovider.GitProvider providerFound := false - gitProviders, err := s.configStore.List() + gitProviders, err := s.configStore.List(ctx) if err != nil { return "", err } @@ -91,7 +73,7 @@ func (s *GitProviderService) GetLastCommitSha(repo *gitprovider.GitRepository) ( isAwsUrl := strings.Contains(repo.Url, ".amazonaws.com/") || strings.Contains(repo.Url, ".console.aws.amazon.com/") if p.ProviderId == "aws-codecommit" && isAwsUrl { - provider, err = s.GetGitProvider(p.ProviderId) + provider, err = s.GetGitProvider(ctx, p.ProviderId) if err == nil { return "", err } @@ -100,7 +82,7 @@ func (s *GitProviderService) GetLastCommitSha(repo *gitprovider.GitRepository) ( } if strings.Contains(repo.Url, fmt.Sprintf("%s.", p.ProviderId)) { - provider, err = s.GetGitProvider(p.ProviderId) + provider, err = s.GetGitProvider(ctx, p.ProviderId) if err == nil { return "", err } @@ -114,7 +96,7 @@ func (s *GitProviderService) GetLastCommitSha(repo *gitprovider.GitRepository) ( } if p.BaseApiUrl != nil && strings.Contains(repo.Url, hostname) { - provider, err = s.GetGitProvider(p.ProviderId) + provider, err = s.GetGitProvider(ctx, p.ProviderId) if err == nil { return "", err } @@ -128,7 +110,7 @@ func (s *GitProviderService) GetLastCommitSha(repo *gitprovider.GitRepository) ( hostname := strings.TrimPrefix(repo.Source, "www.") providerId := strings.Split(hostname, ".")[0] - provider, err = s.newGitProvider(&gitprovider.GitProviderConfig{ + provider, err = s.newGitProvider(&models.GitProviderConfig{ Id: "", ProviderId: providerId, Username: "", @@ -153,7 +135,7 @@ func (s *GitProviderService) GetLastCommitSha(repo *gitprovider.GitRepository) ( }) } -func (s *GitProviderService) newGitProvider(config *gitprovider.GitProviderConfig) (gitprovider.GitProvider, error) { +func (s *GitProviderService) newGitProvider(config *models.GitProviderConfig) (gitprovider.GitProvider, error) { baseApiUrl := "" if config.BaseApiUrl != nil { baseApiUrl = *config.BaseApiUrl diff --git a/pkg/server/gitproviders/user.go b/pkg/server/gitproviders/user.go index 8804734121..583ed05de7 100644 --- a/pkg/server/gitproviders/user.go +++ b/pkg/server/gitproviders/user.go @@ -4,13 +4,14 @@ package gitproviders import ( + "context" "fmt" "github.com/daytonaio/daytona/pkg/gitprovider" ) -func (s *GitProviderService) GetGitUser(gitProviderId string) (*gitprovider.GitUser, error) { - gitProvider, err := s.GetGitProvider(gitProviderId) +func (s *GitProviderService) GetGitUser(ctx context.Context, gitProviderId string) (*gitprovider.GitUser, error) { + gitProvider, err := s.GetGitProvider(ctx, gitProviderId) if err != nil { return nil, fmt.Errorf("failed to get git provider: %w", err) } diff --git a/pkg/server/headscale/auth_keys.go b/pkg/server/headscale/auth_keys.go index 9a26acc389..e1f825cc7d 100644 --- a/pkg/server/headscale/auth_keys.go +++ b/pkg/server/headscale/auth_keys.go @@ -13,12 +13,12 @@ import ( log "github.com/sirupsen/logrus" ) -func (s *HeadscaleServer) CreateAuthKey() (string, error) { +func (s *HeadscaleServer) CreateAuthKey(username string) (string, error) { log.Debug("Creating headscale auth key") request := &v1.CreatePreAuthKeyRequest{ Reusable: false, - User: "daytona", + User: username, Ephemeral: true, Expiration: timestamppb.New(time.Now().Add(100000 * time.Hour)), } diff --git a/pkg/server/headscale/connect.go b/pkg/server/headscale/connect.go index 5e9107194a..b20347d3b5 100644 --- a/pkg/server/headscale/connect.go +++ b/pkg/server/headscale/connect.go @@ -20,13 +20,13 @@ var tsNetServer = &tsnet.Server{ Hostname: "server", } -func (s *HeadscaleServer) Connect() error { - err := s.CreateUser() +func (s *HeadscaleServer) Connect(username string) error { + err := s.CreateUser(username) if err != nil { log.Fatal(err) } - authKey, err := s.CreateAuthKey() + authKey, err := s.CreateAuthKey(username) if err != nil { log.Fatal(err) } diff --git a/pkg/server/headscale/create_user.go b/pkg/server/headscale/create_user.go index 231f650148..e6e9820c8a 100644 --- a/pkg/server/headscale/create_user.go +++ b/pkg/server/headscale/create_user.go @@ -9,7 +9,9 @@ import ( log "github.com/sirupsen/logrus" ) -func (s *HeadscaleServer) CreateUser() error { +const HEADSCALE_USERNAME = "daytona" + +func (s *HeadscaleServer) CreateUser(username string) error { log.Debug("Creating headscale user") ctx, client, conn, cancel, err := s.getClient() @@ -20,7 +22,7 @@ func (s *HeadscaleServer) CreateUser() error { defer conn.Close() _, err = client.GetUser(ctx, &v1.GetUserRequest{ - Name: "daytona", + Name: username, }) if err == nil { log.Debug("User already exists") @@ -28,7 +30,7 @@ func (s *HeadscaleServer) CreateUser() error { } _, err = client.CreateUser(ctx, &v1.CreateUserRequest{ - Name: "daytona", + Name: username, }) return err diff --git a/pkg/server/headscale/server.go b/pkg/server/headscale/server.go index 19836d7f23..a959199f4a 100644 --- a/pkg/server/headscale/server.go +++ b/pkg/server/headscale/server.go @@ -126,10 +126,5 @@ func (s *HeadscaleServer) Stop() error { } func (s *HeadscaleServer) Purge() error { - err := s.Stop() - if err != nil { - return err - } - return os.RemoveAll(s.configDir) } diff --git a/pkg/server/jobs/service.go b/pkg/server/jobs/service.go new file mode 100644 index 0000000000..9924742ed5 --- /dev/null +++ b/pkg/server/jobs/service.go @@ -0,0 +1,185 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package jobs + +import ( + "context" + "errors" + "slices" + + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/services" + "github.com/daytonaio/daytona/pkg/stores" + "github.com/daytonaio/daytona/pkg/telemetry" + "github.com/docker/docker/pkg/stringid" + + log "github.com/sirupsen/logrus" +) + +type JobServiceConfig struct { + JobStore stores.JobStore + TrackTelemetryEvent func(event telemetry.Event, clientId string) error + + UpdateWorkspaceLastJob func(ctx context.Context, workspaceId string, jobId string) error + UpdateTargetLastJob func(ctx context.Context, targetId string, jobId string) error + UpdateBuildLastJob func(ctx context.Context, buildId string, jobId string) error +} + +type JobService struct { + jobStore stores.JobStore + trackTelemetryEvent func(event telemetry.Event, clientId string) error + + updateWorkspaceLastJob func(ctx context.Context, workspaceId string, jobId string) error + updateTargetLastJob func(ctx context.Context, targetId string, jobId string) error + updateBuildLastJob func(ctx context.Context, buildId string, jobId string) error +} + +func NewJobService(config JobServiceConfig) services.IJobService { + return &JobService{ + jobStore: config.JobStore, + trackTelemetryEvent: config.TrackTelemetryEvent, + updateWorkspaceLastJob: config.UpdateWorkspaceLastJob, + updateTargetLastJob: config.UpdateTargetLastJob, + updateBuildLastJob: config.UpdateBuildLastJob, + } +} + +func (s *JobService) List(ctx context.Context, filter *stores.JobFilter) ([]*models.Job, error) { + return s.jobStore.List(ctx, filter) +} + +func (s *JobService) Find(ctx context.Context, filter *stores.JobFilter) (*models.Job, error) { + return s.jobStore.Find(ctx, filter) +} + +func (s *JobService) Create(ctx context.Context, j *models.Job) error { + validAction, ok := validResourceActions[j.ResourceType] + if !ok { + return s.handleCreateError(ctx, j, services.ErrInvalidResourceJobAction) + } + + if !slices.Contains(validAction, j.Action) { + return s.handleCreateError(ctx, j, services.ErrInvalidResourceJobAction) + } + + pendingJobs, err := s.List(ctx, &stores.JobFilter{ + ResourceId: &j.ResourceId, + ResourceType: &j.ResourceType, + States: &[]models.JobState{models.JobStatePending, models.JobStateRunning}, + }) + if err != nil { + return s.handleCreateError(ctx, j, err) + } + + if len(pendingJobs) > 0 { + return s.handleCreateError(ctx, j, stores.ErrJobInProgress) + } + + if j.Id == "" { + id := stringid.GenerateRandomID() + id = stringid.TruncateID(id) + j.Id = id + } + + err = s.jobStore.Save(ctx, j) + return s.handleCreateError(ctx, j, err) +} + +func (s *JobService) UpdateState(ctx context.Context, jobId string, updateJobStateDto services.UpdateJobStateDTO) error { + var err error + ctx, err = s.jobStore.BeginTransaction(ctx) + if err != nil { + return err + } + + defer stores.RecoverAndRollback(ctx, s.jobStore) + + job, findErr := s.Find(ctx, &stores.JobFilter{ + Id: &jobId, + }) + if findErr != nil { + return s.jobStore.RollbackTransaction(ctx, findErr) + } + + if job.State == updateJobStateDto.State { + return s.jobStore.RollbackTransaction(ctx, errors.New("job is already in the specified state")) + } + + job.State = updateJobStateDto.State + job.Error = updateJobStateDto.ErrorMessage + + err = s.jobStore.Save(ctx, job) + if err != nil { + return s.jobStore.RollbackTransaction(ctx, err) + } + + switch job.ResourceType { + case models.ResourceTypeWorkspace: + err = s.updateWorkspaceLastJob(ctx, job.ResourceId, job.Id) + case models.ResourceTypeTarget: + err = s.updateTargetLastJob(ctx, job.ResourceId, job.Id) + case models.ResourceTypeBuild: + err = s.updateBuildLastJob(ctx, job.ResourceId, job.Id) + } + + if err != nil { + return s.jobStore.RollbackTransaction(ctx, err) + } + + return s.jobStore.CommitTransaction(ctx) +} + +func (s *JobService) Delete(ctx context.Context, j *models.Job) error { + return s.jobStore.Delete(ctx, j) +} + +func (s *JobService) handleCreateError(ctx context.Context, j *models.Job, err error) error { + if !telemetry.TelemetryEnabled(ctx) { + return err + } + + clientId := telemetry.ClientId(ctx) + + eventName := telemetry.JobEventLifecycleCreated + if err != nil { + eventName = telemetry.JobEventLifecycleCreationFailed + } + event := telemetry.NewJobEvent(eventName, j, err, nil) + + telemetryError := s.trackTelemetryEvent(event, clientId) + if telemetryError != nil { + log.Trace(telemetryError) + } + + return err +} + +var validResourceActions = map[models.ResourceType][]models.JobAction{ + models.ResourceTypeWorkspace: { + models.JobActionCreate, + models.JobActionStart, + models.JobActionStop, + models.JobActionRestart, + models.JobActionDelete, + models.JobActionForceDelete, + }, + models.ResourceTypeTarget: { + models.JobActionCreate, + models.JobActionStart, + models.JobActionStop, + models.JobActionRestart, + models.JobActionDelete, + models.JobActionForceDelete, + }, + models.ResourceTypeBuild: { + models.JobActionRun, + models.JobActionDelete, + models.JobActionForceDelete, + }, + models.ResourceTypeRunner: { + models.JobActionInstallProvider, + models.JobActionUninstallProvider, + models.JobActionUpdateProvider, + }, +} diff --git a/pkg/server/jobs/service_test.go b/pkg/server/jobs/service_test.go new file mode 100644 index 0000000000..906979f952 --- /dev/null +++ b/pkg/server/jobs/service_test.go @@ -0,0 +1,167 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package jobs_test + +import ( + "context" + "testing" + + job_internal "github.com/daytonaio/daytona/internal/testing/job" + "github.com/daytonaio/daytona/pkg/models" + jobs "github.com/daytonaio/daytona/pkg/server/jobs" + "github.com/daytonaio/daytona/pkg/services" + "github.com/daytonaio/daytona/pkg/stores" + "github.com/daytonaio/daytona/pkg/telemetry" + "github.com/stretchr/testify/suite" +) + +var expectedJobs []*models.Job + +var job1 = &models.Job{ + Id: "1", + ResourceId: "1", + ResourceType: models.ResourceTypeWorkspace, + Action: models.JobActionStart, + State: models.JobStatePending, +} + +var job2 = &models.Job{ + Id: "2", + ResourceId: "2", + ResourceType: models.ResourceTypeWorkspace, + Action: models.JobActionStart, + State: models.JobStatePending, +} + +var job3 = &models.Job{ + Id: "3", + ResourceId: "3", + ResourceType: models.ResourceTypeWorkspace, + Action: models.JobActionStart, + State: models.JobStatePending, +} + +var job4 = &models.Job{ + Id: "4", + ResourceId: "4", + ResourceType: models.ResourceTypeWorkspace, + Action: models.JobActionStart, + State: models.JobStatePending, +} + +type JobServiceTestSuite struct { + suite.Suite + jobService services.IJobService + jobStore stores.JobStore +} + +func NewJobServiceTestSuite() *JobServiceTestSuite { + return &JobServiceTestSuite{} +} + +func (s *JobServiceTestSuite) SetupTest() { + expectedJobs = []*models.Job{ + job1, job2, job3, + } + + s.jobStore = job_internal.NewInMemoryJobStore() + s.jobService = jobs.NewJobService(jobs.JobServiceConfig{ + JobStore: s.jobStore, + TrackTelemetryEvent: func(event telemetry.Event, clientId string) error { + return nil + }, + }) + + for _, j := range expectedJobs { + _ = s.jobStore.Save(context.TODO(), j) + } +} + +func TestJobService(t *testing.T) { + suite.Run(t, NewJobServiceTestSuite()) +} + +func (s *JobServiceTestSuite) TestList() { + require := s.Require() + + jobs, err := s.jobService.List(context.TODO(), nil) + require.Nil(err) + require.ElementsMatch(expectedJobs, jobs) +} + +func (s *JobServiceTestSuite) TestFind() { + require := s.Require() + + job, err := s.jobService.Find(context.TODO(), &stores.JobFilter{ + Id: &job1.Id, + }) + require.Nil(err) + require.Equal(job1, job) +} + +func (s *JobServiceTestSuite) TestCreate() { + expectedJobs = append(expectedJobs, job4) + + require := s.Require() + + err := s.jobService.Create(context.TODO(), job4) + require.Nil(err) + + jobs, err := s.jobService.List(context.TODO(), nil) + require.Nil(err) + require.ElementsMatch(expectedJobs, jobs) +} + +func (s *JobServiceTestSuite) TestSetState() { + require := s.Require() + + err := s.jobService.Create(context.TODO(), job4) + require.Nil(err) + + job4Update := *job4 + job4Update.State = models.JobStateSuccess + + err = s.jobService.UpdateState(context.TODO(), job4Update.Id, services.UpdateJobStateDTO{ + State: models.JobStateSuccess, + ErrorMessage: nil, + }) + require.Nil(err) + + updated, err := s.jobService.Find(context.TODO(), &stores.JobFilter{ + Id: &job4.Id, + }) + require.Nil(err) + require.Equal(job4Update, *updated) +} + +func (s *JobServiceTestSuite) TestCreateWithAnotherJobInProgress() { + require := s.Require() + + err := s.jobService.Create(context.TODO(), job4) + require.Nil(err) + + var job5 = &models.Job{ + Id: "5", + ResourceId: "4", + ResourceType: models.ResourceTypeWorkspace, + Action: models.JobActionStart, + State: models.JobStatePending, + } + + err = s.jobService.Create(context.TODO(), job5) + require.EqualError(err, stores.ErrJobInProgress.Error()) +} + +func (s *JobServiceTestSuite) TestDelete() { + expectedJobs = expectedJobs[:2] + + require := s.Require() + + err := s.jobService.Delete(context.TODO(), job3) + require.Nil(err) + + jobs, err := s.jobService.List(context.TODO(), nil) + require.Nil(err) + require.ElementsMatch(expectedJobs, jobs) +} diff --git a/pkg/server/log.go b/pkg/server/log.go index 7ca329ae99..aed0a48990 100644 --- a/pkg/server/log.go +++ b/pkg/server/log.go @@ -11,7 +11,7 @@ import ( "regexp" "github.com/daytonaio/daytona/internal/constants" - "github.com/daytonaio/daytona/internal/util" + "github.com/daytonaio/daytona/pkg/logs" frp_log "github.com/fatedier/frp/pkg/util/log" log "github.com/sirupsen/logrus" "gopkg.in/natefinch/lumberjack.v2" @@ -42,9 +42,9 @@ func (f *logFormatter) Format(entry *log.Entry) ([]byte, error) { func (s *Server) initLogs() error { rotatedLogFile := &lumberjack.Logger{ Filename: s.config.LogFile.Path, - MaxSize: s.config.LogFile.MaxSize, // megabytes - MaxBackups: s.config.LogFile.MaxBackups, - MaxAge: s.config.LogFile.MaxAge, // days + MaxSize: int(s.config.LogFile.MaxSize), // megabytes + MaxBackups: int(s.config.LogFile.MaxBackups), + MaxAge: int(s.config.LogFile.MaxAge), // days LocalTime: s.config.LogFile.LocalTime, Compress: s.config.LogFile.Compress, } @@ -86,7 +86,7 @@ func (s *Server) GetLogReader(logFileQuery string) (io.Reader, error) { var reader io.Reader if regexp.MustCompile(constants.ZIP_LOG_FILE_NAME_SUFFIX_PATTERN).MatchString(logFileQuery) { - reader, err = util.ReadCompressedFile(logFilePath) + reader, err = logs.ReadCompressedFile(logFilePath) } else { reader, err = os.Open(logFilePath) } diff --git a/pkg/server/profiledata/service.go b/pkg/server/profiledata/service.go deleted file mode 100644 index 3e1ca818ce..0000000000 --- a/pkg/server/profiledata/service.go +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package profiledata - -import ( - . "github.com/daytonaio/daytona/pkg/profiledata" -) - -type IProfileDataService interface { - Get() (*ProfileData, error) - Save(profileData *ProfileData) error - Delete() error -} - -type ProfileDataServiceConfig struct { - ProfileDataStore Store -} - -func NewProfileDataService(config ProfileDataServiceConfig) IProfileDataService { - return &ProfileDataService{ - profileDataStore: config.ProfileDataStore, - } -} - -type ProfileDataService struct { - profileDataStore Store -} - -func (s *ProfileDataService) Get() (*ProfileData, error) { - return s.profileDataStore.Get() -} - -func (s *ProfileDataService) Save(profileData *ProfileData) error { - return s.profileDataStore.Save(profileData) -} - -func (s *ProfileDataService) Delete() error { - return s.profileDataStore.Delete() -} diff --git a/pkg/server/profiledata/service_test.go b/pkg/server/profiledata/service_test.go deleted file mode 100644 index b73af6ce99..0000000000 --- a/pkg/server/profiledata/service_test.go +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package profiledata_test - -import ( - "testing" - - t_profiledata "github.com/daytonaio/daytona/internal/testing/server/profiledata" - . "github.com/daytonaio/daytona/pkg/profiledata" - "github.com/daytonaio/daytona/pkg/server/profiledata" - "github.com/stretchr/testify/suite" -) - -type ProfileDataServiceTestSuite struct { - suite.Suite - profileDataService profiledata.IProfileDataService - profileDataStore Store -} - -func NewApiKeyServiceTestSuite() *ProfileDataServiceTestSuite { - return &ProfileDataServiceTestSuite{} -} - -func (s *ProfileDataServiceTestSuite) SetupTest() { - s.profileDataStore = t_profiledata.NewInMemoryProfileDataStore() - s.profileDataService = profiledata.NewProfileDataService(profiledata.ProfileDataServiceConfig{ - ProfileDataStore: s.profileDataStore, - }) -} - -func TestApiKeyService(t *testing.T) { - suite.Run(t, NewApiKeyServiceTestSuite()) -} - -func (s *ProfileDataServiceTestSuite) TestReturnsProfileDataNotFound() { - profileData, err := s.profileDataService.Get() - s.Require().Nil(profileData) - s.Require().True(IsProfileDataNotFound(err)) -} - -func (s *ProfileDataServiceTestSuite) TestSaveProfileData() { - profileData := &ProfileData{ - EnvVars: map[string]string{ - "key1": "value1", - }, - } - - err := s.profileDataService.Save(profileData) - s.Require().Nil(err) - - profileDataFromStore, err := s.profileDataStore.Get() - s.Require().Nil(err) - s.Require().NotNil(profileDataFromStore) - s.Require().Equal(profileData, profileDataFromStore) -} - -func (s *ProfileDataServiceTestSuite) TestDeleteProfileData() { - profileData := &ProfileData{ - EnvVars: map[string]string{ - "key1": "value1", - }, - } - - err := s.profileDataService.Save(profileData) - s.Require().Nil(err) - - err = s.profileDataService.Delete() - s.Require().Nil(err) - - profileDataFromStore, err := s.profileDataStore.Get() - s.Require().Nil(profileDataFromStore) - s.Require().True(IsProfileDataNotFound(err)) -} diff --git a/pkg/server/projectconfig/dto/projectconfig.go b/pkg/server/projectconfig/dto/projectconfig.go deleted file mode 100644 index 9ff6ab4082..0000000000 --- a/pkg/server/projectconfig/dto/projectconfig.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package dto - -import ( - "github.com/daytonaio/daytona/pkg/workspace/project/buildconfig" -) - -type CreateProjectConfigDTO struct { - Name string `json:"name" validate:"required"` - Image *string `json:"image,omitempty" validate:"optional"` - User *string `json:"user,omitempty" validate:"optional"` - BuildConfig *buildconfig.BuildConfig `json:"buildConfig,omitempty" validate:"optional"` - RepositoryUrl string `json:"repositoryUrl" validate:"required"` - EnvVars map[string]string `json:"envVars" validate:"required"` - GitProviderConfigId *string `json:"gitProviderConfigId" validate:"optional"` -} // @name CreateProjectConfigDTO - -type PrebuildDTO struct { - Id string `json:"id" validate:"required"` - ProjectConfigName string `json:"projectConfigName" validate:"required"` - Branch string `json:"branch" validate:"required"` - CommitInterval *int `json:"commitInterval" validate:"optional"` - TriggerFiles []string `json:"triggerFiles" validate:"optional"` - Retention int `json:"retention" validate:"required"` -} // @name PrebuildDTO - -type CreatePrebuildDTO struct { - Id *string `json:"id" validate:"optional"` - Branch string `json:"branch" validate:"optional"` - CommitInterval *int `json:"commitInterval" validate:"optional"` - TriggerFiles []string `json:"triggerFiles" validate:"optional"` - Retention int `json:"retention" validate:"required"` -} // @name CreatePrebuildDTO diff --git a/pkg/server/projectconfig/prebuild.go b/pkg/server/projectconfig/prebuild.go deleted file mode 100644 index 5c28533bdf..0000000000 --- a/pkg/server/projectconfig/prebuild.go +++ /dev/null @@ -1,417 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package projectconfig - -import ( - "errors" - "fmt" - "sort" - - "github.com/daytonaio/daytona/internal/util" - "github.com/daytonaio/daytona/pkg/build" - "github.com/daytonaio/daytona/pkg/gitprovider" - build_dto "github.com/daytonaio/daytona/pkg/server/builds/dto" - "github.com/daytonaio/daytona/pkg/server/projectconfig/dto" - "github.com/daytonaio/daytona/pkg/workspace/project/config" - "github.com/daytonaio/daytona/pkg/workspace/project/containerconfig" - log "github.com/sirupsen/logrus" -) - -func (s *ProjectConfigService) SetPrebuild(projectConfigName string, createPrebuildDto dto.CreatePrebuildDTO) (*dto.PrebuildDTO, error) { - projectConfig, err := s.Find(&config.ProjectConfigFilter{ - Name: &projectConfigName, - }) - if err != nil { - return nil, err - } - - existingPrebuild, _ := projectConfig.FindPrebuild(&config.PrebuildFilter{ - Branch: &createPrebuildDto.Branch, - }) - - if existingPrebuild != nil && createPrebuildDto.Id == nil { - return nil, errors.New("prebuild for the specified project config and branch already exists") - } - - if createPrebuildDto.CommitInterval == nil && len(createPrebuildDto.TriggerFiles) == 0 { - return nil, errors.New("either the commit interval or trigger files must be specified") - } - - gitProvider, gitProviderId, err := s.gitProviderService.GetGitProviderForUrl(projectConfig.RepositoryUrl) - if err != nil { - return nil, err - } - - repository, err := gitProvider.GetRepositoryContext(gitprovider.GetRepositoryContext{ - Url: projectConfig.RepositoryUrl, - }) - if err != nil { - return nil, err - } - - prebuild := &config.PrebuildConfig{ - Branch: createPrebuildDto.Branch, - CommitInterval: createPrebuildDto.CommitInterval, - TriggerFiles: createPrebuildDto.TriggerFiles, - Retention: createPrebuildDto.Retention, - } - - if createPrebuildDto.Id != nil { - prebuild.Id = *createPrebuildDto.Id - } else { - err = prebuild.GenerateId() - if err != nil { - return nil, err - } - } - - err = projectConfig.SetPrebuild(prebuild) - if err != nil { - return nil, err - } - - // Remember the new webhook ID in case config saving fails - newWebhookId := "" - - existingWebhookId, err := s.gitProviderService.GetPrebuildWebhook(gitProviderId, repository, s.prebuildWebhookEndpoint) - if err != nil { - return nil, err - } - - if existingWebhookId == nil { - newWebhookId, err = s.gitProviderService.RegisterPrebuildWebhook(gitProviderId, repository, s.prebuildWebhookEndpoint) - if err != nil { - return nil, err - } - } - - err = s.configStore.Save(projectConfig) - if err != nil { - if newWebhookId != "" { - err = s.gitProviderService.UnregisterPrebuildWebhook(gitProviderId, repository, newWebhookId) - if err != nil { - log.Error(err) - } - } - - return nil, err - } - - return &dto.PrebuildDTO{ - Id: prebuild.Id, - ProjectConfigName: projectConfig.Name, - Branch: prebuild.Branch, - CommitInterval: prebuild.CommitInterval, - TriggerFiles: prebuild.TriggerFiles, - Retention: prebuild.Retention, - }, nil -} - -func (s *ProjectConfigService) FindPrebuild(projectConfigFilter *config.ProjectConfigFilter, prebuildFilter *config.PrebuildFilter) (*dto.PrebuildDTO, error) { - pc, err := s.configStore.Find(projectConfigFilter) - if err != nil { - return nil, config.ErrProjectConfigNotFound - } - - prebuild, err := pc.FindPrebuild(prebuildFilter) - if err != nil { - return nil, err - } - - return &dto.PrebuildDTO{ - Id: prebuild.Id, - ProjectConfigName: pc.Name, - Branch: prebuild.Branch, - CommitInterval: prebuild.CommitInterval, - TriggerFiles: prebuild.TriggerFiles, - Retention: prebuild.Retention, - }, nil -} - -func (s *ProjectConfigService) ListPrebuilds(projectConfigFilter *config.ProjectConfigFilter, prebuildFilter *config.PrebuildFilter) ([]*dto.PrebuildDTO, error) { - var result []*dto.PrebuildDTO - pcs, err := s.configStore.List(projectConfigFilter) - if err != nil { - return nil, config.ErrProjectConfigNotFound - } - - for _, pc := range pcs { - for _, prebuild := range pc.Prebuilds { - result = append(result, &dto.PrebuildDTO{ - Id: prebuild.Id, - ProjectConfigName: pc.Name, - Branch: prebuild.Branch, - CommitInterval: prebuild.CommitInterval, - TriggerFiles: prebuild.TriggerFiles, - Retention: prebuild.Retention, - }) - } - } - - return result, nil -} - -func (s *ProjectConfigService) DeletePrebuild(projectConfigName string, id string, force bool) []error { - projectConfig, err := s.Find(&config.ProjectConfigFilter{ - Name: &projectConfigName, - }) - if err != nil { - return []error{err} - } - - // Get all prebuilds for this project config's repository URL and - // if this is the last prebuild, unregister the Git provider webhook - prebuilds, err := s.ListPrebuilds(&config.ProjectConfigFilter{ - Url: &projectConfig.RepositoryUrl, - }, nil) - if err != nil { - return []error{err} - } - - if len(prebuilds) == 1 { - gitProvider, gitProviderId, err := s.gitProviderService.GetGitProviderForUrl(projectConfig.RepositoryUrl) - if err != nil { - return []error{err} - } - - repository, err := gitProvider.GetRepositoryContext(gitprovider.GetRepositoryContext{ - Url: projectConfig.RepositoryUrl, - }) - if err != nil { - return []error{err} - } - - existingWebhookId, err := s.gitProviderService.GetPrebuildWebhook(gitProviderId, repository, s.prebuildWebhookEndpoint) - if err != nil { - if force { - log.Error(err) - } else { - return []error{err} - } - } - - if existingWebhookId != nil { - err = s.gitProviderService.UnregisterPrebuildWebhook(gitProviderId, repository, *existingWebhookId) - if err != nil { - if force { - log.Error(err) - } else { - return []error{err} - } - } - } - } - - errs := s.buildService.MarkForDeletion(&build.Filter{ - PrebuildIds: &[]string{id}, - }, force) - if len(errs) > 0 { - if force { - for _, err := range errs { - log.Error(err) - } - } else { - return errs - } - } - - err = projectConfig.RemovePrebuild(id) - if err != nil { - return []error{err} - } - - err = s.configStore.Save(projectConfig) - if err != nil { - return []error{err} - } - - return nil -} - -func (s *ProjectConfigService) ProcessGitEvent(data gitprovider.GitEventData) error { - var buildsToTrigger []build.Build - - projectConfigs, err := s.List(&config.ProjectConfigFilter{ - Url: &data.Url, - }) - if err != nil { - return err - } - gitProvider, _, err := s.gitProviderService.GetGitProviderForUrl(data.Url) - if err != nil { - return fmt.Errorf("failed to get git provider for URL: %s", err) - } - - repo, err := gitProvider.GetRepositoryContext(gitprovider.GetRepositoryContext{ - Url: data.Url, - }) - if err != nil { - return fmt.Errorf("failed to get repository context: %s", err) - } - - for _, projectConfig := range projectConfigs { - prebuild, err := projectConfig.FindPrebuild(&config.PrebuildFilter{ - Branch: &data.Branch, - }) - if err != nil || prebuild == nil { - continue - } - - // Check if the commit's affected files and prebuild config's trigger files have any overlap - if len(prebuild.TriggerFiles) > 0 { - if slicesHaveCommonEntry(prebuild.TriggerFiles, data.AffectedFiles) { - buildsToTrigger = append(buildsToTrigger, build.Build{ - ContainerConfig: containerconfig.ContainerConfig{ - Image: projectConfig.Image, - User: projectConfig.User, - }, - BuildConfig: projectConfig.BuildConfig, - Repository: repo, - EnvVars: projectConfig.EnvVars, - PrebuildId: prebuild.Id, - }) - continue - } - } - - newestBuild, err := s.buildService.Find(&build.Filter{ - PrebuildIds: &[]string{prebuild.Id}, - GetNewest: util.Pointer(true), - }) - if err != nil { - buildsToTrigger = append(buildsToTrigger, build.Build{ - ContainerConfig: containerconfig.ContainerConfig{ - Image: projectConfig.Image, - User: projectConfig.User, - }, - BuildConfig: projectConfig.BuildConfig, - Repository: repo, - EnvVars: projectConfig.EnvVars, - PrebuildId: prebuild.Id, - }) - continue - } - - commitsRange, err := gitProvider.GetCommitsRange(repo, newestBuild.Repository.Sha, data.Sha) - if err != nil { - return fmt.Errorf("failed to get commits range: %s", err) - } - - // Check if the commit interval has been reached - if prebuild.CommitInterval != nil && commitsRange >= *prebuild.CommitInterval { - buildsToTrigger = append(buildsToTrigger, build.Build{ - ContainerConfig: containerconfig.ContainerConfig{ - Image: projectConfig.Image, - User: projectConfig.User, - }, - BuildConfig: projectConfig.BuildConfig, - Repository: repo, - EnvVars: projectConfig.EnvVars, - PrebuildId: prebuild.Id, - }) - } - } - - for _, build := range buildsToTrigger { - createBuildDto := build_dto.BuildCreationData{ - Image: build.ContainerConfig.Image, - User: build.ContainerConfig.User, - BuildConfig: build.BuildConfig, - Repository: build.Repository, - EnvVars: build.EnvVars, - PrebuildId: build.PrebuildId, - } - - _, err = s.buildService.Create(createBuildDto) - if err != nil { - return fmt.Errorf("failed to create build: %s", err) - } - } - - return nil -} - -// Marks the [retention] oldest published builds for deletion for each prebuild -func (s *ProjectConfigService) EnforceRetentionPolicy() error { - prebuilds, err := s.ListPrebuilds(nil, nil) - if err != nil { - return err - } - - builds, err := s.buildService.List(&build.Filter{ - States: &[]build.BuildState{build.BuildStatePublished}, - }) - if err != nil { - return err - } - - buildMap := make(map[string][]build.Build) - - // Group builds by their prebuildId - for _, b := range builds { - buildMap[b.PrebuildId] = append(buildMap[b.PrebuildId], *b) - } - - for _, prebuild := range prebuilds { - - associatedBuilds := buildMap[prebuild.Id] - - if len(associatedBuilds) > prebuild.Retention { - // Sort the builds by creation time in ascending order (oldest first) - sort.Slice(associatedBuilds, func(i, j int) bool { - return associatedBuilds[i].CreatedAt.Before(associatedBuilds[j].CreatedAt) - }) - - numToDelete := len(associatedBuilds) - prebuild.Retention - - // Mark the oldest builds for deletion - for i := 0; i < numToDelete; i++ { - errs := s.buildService.MarkForDeletion(&build.Filter{ - Id: &associatedBuilds[i].Id, - }, false) - if len(errs) > 0 { - for _, err := range errs { - log.Error(err) - } - } - } - } - - } - - return nil -} - -func (s *ProjectConfigService) StartRetentionPoller() error { - scheduler := build.NewCronScheduler() - - err := scheduler.AddFunc(build.DEFAULT_POLL_INTERVAL, func() { - err := s.EnforceRetentionPolicy() - if err != nil { - log.Error(err) - } - }) - if err != nil { - return err - } - - scheduler.Start() - return nil -} - -func slicesHaveCommonEntry(slice1, slice2 []string) bool { - entryMap := make(map[string]bool) - - for _, entry := range slice1 { - entryMap[entry] = true - } - - for _, entry := range slice2 { - if entryMap[entry] { - return true - } - } - - return false -} diff --git a/pkg/server/projectconfig/prebuild_test.go b/pkg/server/projectconfig/prebuild_test.go deleted file mode 100644 index d780a30186..0000000000 --- a/pkg/server/projectconfig/prebuild_test.go +++ /dev/null @@ -1,235 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package projectconfig_test - -import ( - "time" - - "github.com/daytonaio/daytona/internal/util" - "github.com/daytonaio/daytona/pkg/build" - "github.com/daytonaio/daytona/pkg/gitprovider" - build_dto "github.com/daytonaio/daytona/pkg/server/builds/dto" - "github.com/daytonaio/daytona/pkg/server/projectconfig/dto" - "github.com/daytonaio/daytona/pkg/workspace/project/config" -) - -var prebuild1 *config.PrebuildConfig = &config.PrebuildConfig{ - Id: "1", - Branch: "feat", - CommitInterval: util.Pointer(3), - Retention: 3, - TriggerFiles: []string{"file1", "file2"}, -} - -var prebuild2 *config.PrebuildConfig = &config.PrebuildConfig{ - Id: "2", - Branch: "dev", - CommitInterval: util.Pointer(1), - Retention: 3, - TriggerFiles: []string{"file1", "file2"}, -} - -var prebuild3 *config.PrebuildConfig = &config.PrebuildConfig{ - Id: "3", - Branch: "new", - CommitInterval: util.Pointer(1), - Retention: 3, - TriggerFiles: []string{"file1", "file2"}, -} - -var prebuild1Dto *dto.PrebuildDTO = &dto.PrebuildDTO{ - ProjectConfigName: projectConfig1.Name, - Id: prebuild1.Id, - Branch: prebuild1.Branch, - CommitInterval: prebuild1.CommitInterval, - Retention: prebuild1.Retention, - TriggerFiles: prebuild1.TriggerFiles, -} - -var repository1 *gitprovider.GitRepository = &gitprovider.GitRepository{ - Url: "https://github.com/daytonaio/daytona.git", - Branch: "main", - Sha: "sha1", -} - -var expectedPrebuilds []*config.PrebuildConfig -var expectedFilteredPrebuilds []*config.PrebuildConfig - -var expectedPrebuildsMap map[string]*config.PrebuildConfig -var expectedFilteredPrebuildsMap map[string]*config.PrebuildConfig - -func (s *ProjectConfigServiceTestSuite) TestSetPrebuild() { - require := s.Require() - - s.gitProviderService.On("GetGitProviderForUrl", repository1.Url).Return(&s.gitProvider, "github", nil) - s.gitProvider.On("GetRepositoryContext", gitprovider.GetRepositoryContext{ - Url: repository1.Url, - }).Return(repository1, nil) - s.gitProviderService.On("GetPrebuildWebhook", "github", repository1, "").Return(util.Pointer("webhook-id"), nil) - - newPrebuildDto, err := s.projectConfigService.SetPrebuild(projectConfig1.Name, dto.CreatePrebuildDTO{ - Id: &prebuild3.Id, - Branch: prebuild3.Branch, - CommitInterval: prebuild3.CommitInterval, - Retention: prebuild3.Retention, - TriggerFiles: prebuild3.TriggerFiles, - }) - require.Nil(err) - - prebuildDtos, err := s.projectConfigService.ListPrebuilds(&config.ProjectConfigFilter{ - Name: &projectConfig1.Name, - }, nil) - require.Nil(err) - require.Contains(prebuildDtos, newPrebuildDto) -} - -func (s *ProjectConfigServiceTestSuite) TestFindPrebuild() { - require := s.Require() - - prebuild, err := s.projectConfigService.FindPrebuild(&config.ProjectConfigFilter{ - Name: &projectConfig1.Name, - }, &config.PrebuildFilter{ - Id: &prebuild1.Id, - }) - require.Nil(err) - require.Equal(prebuild1Dto, prebuild) -} -func (s *ProjectConfigServiceTestSuite) TestListPrebuilds() { - require := s.Require() - - prebuildDtos, err := s.projectConfigService.ListPrebuilds(&config.ProjectConfigFilter{ - Name: &projectConfig1.Name, - }, nil) - require.Nil(err) - - require.Contains(prebuildDtos, prebuild1Dto) -} - -func (s *ProjectConfigServiceTestSuite) TestDeletePrebuild() { - expectedPrebuilds = expectedPrebuilds[:1] - - require := s.Require() - - s.buildService.On("MarkForDeletion", &build.Filter{ - PrebuildIds: &[]string{prebuild2.Id}, - }, false).Return([]error{}) - - err := s.projectConfigService.DeletePrebuild(projectConfig1.Name, prebuild2.Id, false) - require.Nil(err) - - prebuildDtos, errs := s.projectConfigService.ListPrebuilds(&config.ProjectConfigFilter{ - Name: &projectConfig1.Name, - }, nil) - require.Nil(errs) - require.ElementsMatch([]*dto.PrebuildDTO{ - prebuild1Dto, - }, prebuildDtos) -} - -func (s *ProjectConfigServiceTestSuite) TestProcessGitEventCommitInterval() { - require := s.Require() - - s.gitProviderService.On("GetGitProviderForUrl", repository1.Url).Return(&s.gitProvider, "github", nil) - s.gitProvider.On("GetRepositoryContext", gitprovider.GetRepositoryContext{ - Url: repository1.Url, - }).Return(repository1, nil) - - s.buildService.On("Create", build_dto.BuildCreationData{ - PrebuildId: prebuild1.Id, - Repository: repository1, - User: projectConfig1.User, - Image: projectConfig1.Image, - }).Return("", nil) - - s.buildService.On("Find", &build.Filter{ - PrebuildIds: &[]string{prebuild1.Id}, - GetNewest: util.Pointer(true), - }).Return(&build.Build{ - Id: "1", - PrebuildId: prebuild1.Id, - Repository: repository1, - }, nil) - - data := gitprovider.GitEventData{ - Url: repository1.Url, - Branch: "feat", - Sha: "sha4", - Owner: repository1.Owner, - AffectedFiles: []string{}, - } - - s.gitProvider.On("GetCommitsRange", repository1, repository1.Sha, data.Sha).Return(3, nil) - - err := s.projectConfigService.ProcessGitEvent(data) - require.Nil(err) -} - -func (s *ProjectConfigServiceTestSuite) TestProcessGitEventTriggerFiles() { - require := s.Require() - - s.gitProviderService.On("GetGitProviderForUrl", repository1.Url).Return(&s.gitProvider, "github", nil) - s.gitProvider.On("GetRepositoryContext", gitprovider.GetRepositoryContext{ - Url: repository1.Url, - }).Return(repository1, nil) - - s.buildService.On("Create", build_dto.BuildCreationData{ - PrebuildId: prebuild1.Id, - Repository: repository1, - User: projectConfig1.User, - Image: projectConfig1.Image, - }).Return("", nil) - - data := gitprovider.GitEventData{ - Url: repository1.Url, - Branch: "feat", - Sha: "sha4", - Owner: repository1.Owner, - AffectedFiles: []string{ - "file1", - }, - } - - err := s.projectConfigService.ProcessGitEvent(data) - require.Nil(err) -} - -func (s *ProjectConfigServiceTestSuite) TestEnforceRetentionPolicy() { - require := s.Require() - - s.buildService.On("List", &build.Filter{ - States: &[]build.BuildState{build.BuildStatePublished}, - }).Return([]*build.Build{ - { - Id: "1", - PrebuildId: "1", - State: build.BuildStatePublished, - CreatedAt: time.Now().Add(time.Hour * -4), - }, - { - Id: "2", - PrebuildId: "1", - State: build.BuildStatePublished, - CreatedAt: time.Now().Add(time.Hour * -3), - }, - { - Id: "3", - PrebuildId: "1", - State: build.BuildStatePublished, - CreatedAt: time.Now().Add(time.Hour * -2), - }, - { - Id: "4", - PrebuildId: "1", - State: build.BuildStatePublished, - CreatedAt: time.Now().Add(time.Hour * -1), - }, - }, nil) - - s.buildService.On("MarkForDeletion", &build.Filter{ - Id: util.Pointer("1"), - }, false).Return([]error{}) - - err := s.projectConfigService.EnforceRetentionPolicy() - require.Nil(err) -} diff --git a/pkg/server/projectconfig/service.go b/pkg/server/projectconfig/service.go deleted file mode 100644 index 89e1f7dadd..0000000000 --- a/pkg/server/projectconfig/service.go +++ /dev/null @@ -1,134 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package projectconfig - -import ( - "strings" - - "github.com/daytonaio/daytona/internal/util" - "github.com/daytonaio/daytona/pkg/gitprovider" - "github.com/daytonaio/daytona/pkg/server/builds" - "github.com/daytonaio/daytona/pkg/server/gitproviders" - "github.com/daytonaio/daytona/pkg/server/projectconfig/dto" - "github.com/daytonaio/daytona/pkg/workspace/project/config" -) - -type IProjectConfigService interface { - Save(projectConfig *config.ProjectConfig) error - Find(filter *config.ProjectConfigFilter) (*config.ProjectConfig, error) - List(filter *config.ProjectConfigFilter) ([]*config.ProjectConfig, error) - SetDefault(projectConfigName string) error - Delete(projectConfigName string, force bool) []error - - SetPrebuild(projectConfigName string, createPrebuildDto dto.CreatePrebuildDTO) (*dto.PrebuildDTO, error) - FindPrebuild(projectConfigFilter *config.ProjectConfigFilter, prebuildFilter *config.PrebuildFilter) (*dto.PrebuildDTO, error) - ListPrebuilds(projectConfigFilter *config.ProjectConfigFilter, prebuildFilter *config.PrebuildFilter) ([]*dto.PrebuildDTO, error) - DeletePrebuild(projectConfigName string, id string, force bool) []error - - StartRetentionPoller() error - EnforceRetentionPolicy() error - ProcessGitEvent(gitprovider.GitEventData) error -} - -type ProjectConfigServiceConfig struct { - PrebuildWebhookEndpoint string - ConfigStore config.Store - BuildService builds.IBuildService - GitProviderService gitproviders.IGitProviderService -} - -type ProjectConfigService struct { - prebuildWebhookEndpoint string - configStore config.Store - buildService builds.IBuildService - gitProviderService gitproviders.IGitProviderService -} - -func NewProjectConfigService(config ProjectConfigServiceConfig) IProjectConfigService { - - return &ProjectConfigService{ - prebuildWebhookEndpoint: config.PrebuildWebhookEndpoint, - configStore: config.ConfigStore, - buildService: config.BuildService, - gitProviderService: config.GitProviderService, - } -} - -func (s *ProjectConfigService) List(filter *config.ProjectConfigFilter) ([]*config.ProjectConfig, error) { - return s.configStore.List(filter) -} - -func (s *ProjectConfigService) SetDefault(projectConfigName string) error { - projectConfig, err := s.Find(&config.ProjectConfigFilter{ - Name: &projectConfigName, - }) - if err != nil { - return err - } - - defaultProjectConfig, err := s.Find(&config.ProjectConfigFilter{ - Url: &projectConfig.RepositoryUrl, - Default: util.Pointer(true), - }) - if err != nil && err != config.ErrProjectConfigNotFound { - return err - } - - if defaultProjectConfig != nil { - defaultProjectConfig.IsDefault = false - err := s.configStore.Save(defaultProjectConfig) - if err != nil { - return err - } - } - - projectConfig.IsDefault = true - return s.configStore.Save(projectConfig) -} - -func (s *ProjectConfigService) Find(filter *config.ProjectConfigFilter) (*config.ProjectConfig, error) { - if filter != nil && filter.Url != nil { - cleanedUrl := util.CleanUpRepositoryUrl(*filter.Url) - if !strings.HasSuffix(cleanedUrl, ".git") { - cleanedUrl = cleanedUrl + ".git" - } - filter.Url = util.Pointer(cleanedUrl) - } - return s.configStore.Find(filter) -} - -func (s *ProjectConfigService) Save(projectConfig *config.ProjectConfig) error { - projectConfig.RepositoryUrl = util.CleanUpRepositoryUrl(projectConfig.RepositoryUrl) - - err := s.configStore.Save(projectConfig) - if err != nil { - return err - } - - return s.SetDefault(projectConfig.Name) -} - -func (s *ProjectConfigService) Delete(projectConfigName string, force bool) []error { - pc, err := s.Find(&config.ProjectConfigFilter{ - Name: &projectConfigName, - }) - if err != nil { - return []error{err} - } - - // DeletePrebuild handles deleting the builds and removing the webhook - for _, prebuild := range pc.Prebuilds { - errs := s.DeletePrebuild(pc.Name, prebuild.Id, force) - if len(errs) > 0 { - return errs - } - } - - err = s.configStore.Delete(pc) - if err != nil { - return []error{err} - } - - return nil -} diff --git a/pkg/server/projectconfig/service_test.go b/pkg/server/projectconfig/service_test.go deleted file mode 100644 index b1733cd274..0000000000 --- a/pkg/server/projectconfig/service_test.go +++ /dev/null @@ -1,195 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package projectconfig_test - -import ( - "testing" - - git_provider_mock "github.com/daytonaio/daytona/internal/testing/gitprovider/mocks" - projectconfig_internal "github.com/daytonaio/daytona/internal/testing/server/projectconfig" - "github.com/daytonaio/daytona/internal/testing/server/workspaces/mocks" - "github.com/daytonaio/daytona/internal/util" - "github.com/daytonaio/daytona/pkg/server/projectconfig" - "github.com/daytonaio/daytona/pkg/workspace/project/config" - "github.com/stretchr/testify/suite" -) - -var projectConfig1Image = "image1" -var projectConfig1User = "user1" - -var projectConfig1 *config.ProjectConfig = &config.ProjectConfig{ - Name: "pc1", - Image: projectConfig1Image, - User: projectConfig1User, - BuildConfig: nil, - RepositoryUrl: repository1.Url, - IsDefault: true, - Prebuilds: []*config.PrebuildConfig{ - prebuild1, - prebuild2, - }, -} - -var projectConfig2 *config.ProjectConfig = &config.ProjectConfig{ - Name: "pc2", - Image: "image2", - User: "user2", - BuildConfig: nil, - RepositoryUrl: "https://github.com/daytonaio/daytona.git", -} - -var projectConfig3 *config.ProjectConfig = &config.ProjectConfig{ - Name: "pc3", - Image: "image3", - User: "user3", - BuildConfig: nil, - RepositoryUrl: "https://github.com/daytonaio/daytona3.git", -} - -var projectConfig4 *config.ProjectConfig = &config.ProjectConfig{ - Name: "pc4", - Image: "image4", - User: "user4", - BuildConfig: nil, - RepositoryUrl: "https://github.com/daytonaio/daytona4.git", -} - -var expectedProjectConfigs []*config.ProjectConfig -var expectedFilteredProjectConfigs []*config.ProjectConfig - -var expectedProjectConfigsMap map[string]*config.ProjectConfig -var expectedFilteredProjectConfigsMap map[string]*config.ProjectConfig - -type ProjectConfigServiceTestSuite struct { - suite.Suite - projectConfigService projectconfig.IProjectConfigService - projectConfigStore config.Store - gitProviderService mocks.MockGitProviderService - buildService mocks.MockBuildService - gitProvider git_provider_mock.MockGitProvider -} - -func NewConfigServiceTestSuite() *ProjectConfigServiceTestSuite { - return &ProjectConfigServiceTestSuite{} -} - -func (s *ProjectConfigServiceTestSuite) SetupTest() { - expectedProjectConfigs = []*config.ProjectConfig{ - projectConfig1, projectConfig2, projectConfig3, - } - - expectedPrebuilds = []*config.PrebuildConfig{ - prebuild1, prebuild2, - } - - expectedProjectConfigsMap = map[string]*config.ProjectConfig{ - projectConfig1.Name: projectConfig1, - projectConfig2.Name: projectConfig2, - projectConfig3.Name: projectConfig3, - } - - expectedPrebuildsMap = map[string]*config.PrebuildConfig{ - prebuild1.Id: prebuild1, - prebuild2.Id: prebuild2, - } - - expectedFilteredProjectConfigs = []*config.ProjectConfig{ - projectConfig1, projectConfig2, - } - - expectedFilteredPrebuilds = []*config.PrebuildConfig{ - prebuild1, - } - - expectedFilteredProjectConfigsMap = map[string]*config.ProjectConfig{ - projectConfig1.Name: projectConfig1, - projectConfig2.Name: projectConfig2, - } - - expectedFilteredPrebuildsMap = map[string]*config.PrebuildConfig{ - prebuild1.Id: prebuild1, - } - - s.projectConfigStore = projectconfig_internal.NewInMemoryProjectConfigStore() - s.projectConfigService = projectconfig.NewProjectConfigService(projectconfig.ProjectConfigServiceConfig{ - ConfigStore: s.projectConfigStore, - GitProviderService: &s.gitProviderService, - BuildService: &s.buildService, - }) - - for _, pc := range expectedProjectConfigs { - _ = s.projectConfigStore.Save(pc) - } -} - -func TestProjectConfigService(t *testing.T) { - suite.Run(t, NewConfigServiceTestSuite()) -} - -func (s *ProjectConfigServiceTestSuite) TestList() { - require := s.Require() - - projectConfigs, err := s.projectConfigService.List(nil) - require.Nil(err) - require.ElementsMatch(expectedProjectConfigs, projectConfigs) -} - -func (s *ProjectConfigServiceTestSuite) TestFind() { - require := s.Require() - - projectConfig, err := s.projectConfigService.Find(&config.ProjectConfigFilter{ - Name: &projectConfig1.Name, - }) - require.Nil(err) - require.Equal(projectConfig1, projectConfig) -} -func (s *ProjectConfigServiceTestSuite) TestSetDefault() { - require := s.Require() - - err := s.projectConfigService.SetDefault(projectConfig2.Name) - require.Nil(err) - - projectConfig, err := s.projectConfigService.Find(&config.ProjectConfigFilter{ - Url: util.Pointer(projectConfig1.RepositoryUrl), - Default: util.Pointer(true), - }) - require.Nil(err) - - require.Equal(projectConfig2, projectConfig) -} - -func (s *ProjectConfigServiceTestSuite) TestSave() { - expectedProjectConfigs = append(expectedProjectConfigs, projectConfig4) - - require := s.Require() - - err := s.projectConfigService.Save(projectConfig4) - require.Nil(err) - - projectConfigs, err := s.projectConfigService.List(nil) - require.Nil(err) - require.ElementsMatch(expectedProjectConfigs, projectConfigs) -} - -func (s *ProjectConfigServiceTestSuite) TestDelete() { - expectedProjectConfigs = expectedProjectConfigs[:2] - - require := s.Require() - - err := s.projectConfigService.Delete(projectConfig3.Name, false) - require.Nil(err) - - projectConfigs, errs := s.projectConfigService.List(nil) - require.Nil(errs) - require.ElementsMatch(expectedProjectConfigs, projectConfigs) -} - -func (s *ProjectConfigServiceTestSuite) AfterTest(_, _ string) { - s.gitProviderService.AssertExpectations(s.T()) - s.gitProviderService.ExpectedCalls = nil - s.buildService.AssertExpectations(s.T()) - s.buildService.ExpectedCalls = nil - s.gitProvider.AssertExpectations(s.T()) - s.gitProvider.ExpectedCalls = nil -} diff --git a/pkg/server/providers.go b/pkg/server/providers.go deleted file mode 100644 index 7c55961b47..0000000000 --- a/pkg/server/providers.go +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package server - -import ( - "context" - "errors" - "os" - "path/filepath" - - "github.com/daytonaio/daytona/pkg/provider/manager" - log "github.com/sirupsen/logrus" -) - -func (s *Server) downloadDefaultProviders() error { - manifest, err := s.ProviderManager.GetProvidersManifest() - if err != nil { - return err - } - - defaultProviders := manifest.GetDefaultProviders() - - log.Info("Downloading default providers") - for providerName, provider := range defaultProviders { - lockFilePath := filepath.Join(s.config.ProvidersDir, providerName, manager.INITIAL_SETUP_LOCK_FILE_NAME) - - _, err := os.Stat(lockFilePath) - if err == nil { - continue - } - - _, err = s.ProviderManager.DownloadProvider(context.Background(), provider.DownloadUrls, providerName) - if err != nil { - if !manager.IsProviderAlreadyDownloaded(err, providerName) { - log.Error(err) - } - continue - } - } - - log.Info("Default providers downloaded") - - return nil -} - -func (s *Server) registerProviders() error { - log.Info("Registering providers") - - manifest, err := s.ProviderManager.GetProvidersManifest() - if err != nil { - return err - } - - directoryEntries, err := os.ReadDir(s.config.ProvidersDir) - if err != nil { - if os.IsNotExist(err) { - log.Info("No providers found") - return nil - } - return err - } - - for _, entry := range directoryEntries { - if entry.IsDir() { - providerDir := filepath.Join(s.config.ProvidersDir, entry.Name()) - - pluginPath, err := s.getPluginPath(providerDir) - if err != nil { - if !manager.IsNoPluginFound(err, providerDir) { - log.Error(err) - } - continue - } - - err = s.ProviderManager.RegisterProvider(pluginPath, false) - if err != nil { - log.Error(err) - continue - } - - // Lock the initial setup - lockFilePath := filepath.Join(s.config.ProvidersDir, entry.Name(), manager.INITIAL_SETUP_LOCK_FILE_NAME) - - _, err = os.Stat(lockFilePath) - if err != nil { - file, err := os.Create(lockFilePath) - if err != nil { - return err - } - defer file.Close() - } - - // Check for updates - provider, err := s.ProviderManager.GetProvider(entry.Name()) - if err != nil { - log.Error(err) - continue - } - - info, err := (*provider).GetInfo() - if err != nil { - log.Error(err) - continue - } - requirements, err := (*provider).CheckRequirements() - if err != nil { - return err - } - for _, req := range *requirements { - if req.Met { - log.Infof("Provider requirement met: %s", req.Reason) - } else { - log.Warnf("Provider requirement not met: %s", req.Reason) - } - } - - if manifest.HasUpdateAvailable(info.Name, info.Version) { - log.Infof("Update available for %s. Update with `daytona provider update`.", info.Name) - } - } - } - - log.Info("Providers registered") - - return nil -} - -func (s *Server) getPluginPath(dir string) (string, error) { - files, err := os.ReadDir(dir) - if err != nil { - return "", err - } - - for _, file := range files { - if !file.IsDir() && file.Name() != manager.INITIAL_SETUP_LOCK_FILE_NAME { - return filepath.Join(dir, file.Name()), nil - } - } - - return "", errors.New("no plugin found in " + dir) -} diff --git a/pkg/server/providertargets/dto/providertargets.go b/pkg/server/providertargets/dto/providertargets.go deleted file mode 100644 index fc2e6411cc..0000000000 --- a/pkg/server/providertargets/dto/providertargets.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package dto - -import "github.com/daytonaio/daytona/pkg/provider" - -type CreateProviderTargetDTO struct { - Name string `json:"name" validate:"required"` - ProviderInfo provider.ProviderInfo `json:"providerInfo" validate:"required"` - Options string `json:"options" validate:"required"` -} // @name CreateProviderTargetDTO diff --git a/pkg/server/providertargets/service.go b/pkg/server/providertargets/service.go deleted file mode 100644 index 4a2f22834c..0000000000 --- a/pkg/server/providertargets/service.go +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package providertargets - -import ( - "github.com/daytonaio/daytona/internal/util" - "github.com/daytonaio/daytona/pkg/provider" -) - -type IProviderTargetService interface { - Delete(target *provider.ProviderTarget) error - Find(filter *provider.TargetFilter) (*provider.ProviderTarget, error) - List(filter *provider.TargetFilter) ([]*provider.ProviderTarget, error) - Map() (map[string]*provider.ProviderTarget, error) - Save(target *provider.ProviderTarget) error - SetDefault(target *provider.ProviderTarget) error -} - -type ProviderTargetServiceConfig struct { - TargetStore provider.TargetStore -} - -type ProviderTargetService struct { - targetStore provider.TargetStore -} - -func NewProviderTargetService(config ProviderTargetServiceConfig) IProviderTargetService { - return &ProviderTargetService{ - targetStore: config.TargetStore, - } -} - -func (s *ProviderTargetService) List(filter *provider.TargetFilter) ([]*provider.ProviderTarget, error) { - return s.targetStore.List(filter) -} - -func (s *ProviderTargetService) Map() (map[string]*provider.ProviderTarget, error) { - list, err := s.targetStore.List(nil) - if err != nil { - return nil, err - } - - targets := make(map[string]*provider.ProviderTarget) - for _, target := range list { - targets[target.Name] = target - } - - return targets, nil -} - -func (s *ProviderTargetService) Find(filter *provider.TargetFilter) (*provider.ProviderTarget, error) { - return s.targetStore.Find(filter) -} - -func (s *ProviderTargetService) Save(target *provider.ProviderTarget) error { - err := s.targetStore.Save(target) - if err != nil { - return err - } - - return s.SetDefault(target) -} - -func (s *ProviderTargetService) Delete(target *provider.ProviderTarget) error { - return s.targetStore.Delete(target) -} - -func (s *ProviderTargetService) SetDefault(target *provider.ProviderTarget) error { - currentTarget, err := s.Find(&provider.TargetFilter{ - Name: &target.Name, - }) - if err != nil { - return err - } - - defaultTarget, err := s.Find(&provider.TargetFilter{ - Default: util.Pointer(true), - }) - if err != nil && err != provider.ErrTargetNotFound { - return err - } - - if defaultTarget != nil { - defaultTarget.IsDefault = false - err := s.targetStore.Save(defaultTarget) - if err != nil { - return err - } - } - - currentTarget.IsDefault = true - return s.targetStore.Save(currentTarget) -} diff --git a/pkg/server/providertargets/service_test.go b/pkg/server/providertargets/service_test.go deleted file mode 100644 index 05a14bdbb1..0000000000 --- a/pkg/server/providertargets/service_test.go +++ /dev/null @@ -1,153 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package providertargets_test - -import ( - "testing" - - "github.com/daytonaio/daytona/internal/testing/provider/targets" - "github.com/daytonaio/daytona/pkg/provider" - "github.com/daytonaio/daytona/pkg/server/providertargets" - "github.com/stretchr/testify/suite" -) - -var providerTarget1 *provider.ProviderTarget = &provider.ProviderTarget{ - Name: "target1", - ProviderInfo: provider.ProviderInfo{ - Name: "provider1", - Version: "v1", - }, - Options: "", -} - -var providerTarget2 *provider.ProviderTarget = &provider.ProviderTarget{ - Name: "target2", - ProviderInfo: provider.ProviderInfo{ - Name: "provider2", - Version: "v1", - }, - Options: "", -} - -var providerTarget3 *provider.ProviderTarget = &provider.ProviderTarget{ - Name: "target3", - ProviderInfo: provider.ProviderInfo{ - Name: "provider1", - Version: "v1", - }, - Options: "", -} - -var providerTarget4 *provider.ProviderTarget = &provider.ProviderTarget{ - Name: "new-target", - ProviderInfo: provider.ProviderInfo{ - Name: "provider2", - Version: "v1", - }, - Options: "", -} - -var expectedProviderTargets []*provider.ProviderTarget -var expectedProviderTargetsMap map[string]*provider.ProviderTarget - -type ProviderTargetServiceTestSuite struct { - suite.Suite - providerTargetService providertargets.IProviderTargetService - targetStore provider.TargetStore -} - -func NewProviderTargetServiceTestSuite() *ProviderTargetServiceTestSuite { - return &ProviderTargetServiceTestSuite{} -} - -func (s *ProviderTargetServiceTestSuite) SetupTest() { - expectedProviderTargets = []*provider.ProviderTarget{ - providerTarget1, providerTarget2, providerTarget3, - } - - expectedProviderTargetsMap = map[string]*provider.ProviderTarget{ - providerTarget1.Name: providerTarget1, - providerTarget2.Name: providerTarget2, - providerTarget3.Name: providerTarget3, - } - - s.targetStore = targets.NewInMemoryTargetStore() - s.providerTargetService = providertargets.NewProviderTargetService(providertargets.ProviderTargetServiceConfig{ - TargetStore: s.targetStore, - }) - - for _, target := range expectedProviderTargets { - _ = s.providerTargetService.Save(target) - } -} - -func TestProviderTargetService(t *testing.T) { - suite.Run(t, NewProviderTargetServiceTestSuite()) -} - -func (s *ProviderTargetServiceTestSuite) TestList() { - require := s.Require() - - providerTargets, err := s.providerTargetService.List(nil) - require.Nil(err) - require.ElementsMatch(expectedProviderTargets, providerTargets) -} - -func (s *ProviderTargetServiceTestSuite) TestMap() { - require := s.Require() - - providerTargetsMap, err := s.providerTargetService.Map() - require.Nil(err) - require.Equal(expectedProviderTargetsMap, providerTargetsMap) -} - -func (s *ProviderTargetServiceTestSuite) TestFind() { - require := s.Require() - - providerTarget, err := s.providerTargetService.Find(&provider.TargetFilter{ - Name: &providerTarget1.Name, - }) - require.Nil(err) - require.Equal(providerTarget1, providerTarget) -} - -func (s *ProviderTargetServiceTestSuite) TestSetDefault() { - require := s.Require() - - err := s.providerTargetService.SetDefault(providerTarget2) - require.Nil(err) - - providerTarget, err := s.providerTargetService.Find(&provider.TargetFilter{ - Name: &providerTarget2.Name, - }) - require.Nil(err) - - require.Equal(providerTarget2, providerTarget) -} - -func (s *ProviderTargetServiceTestSuite) TestSave() { - expectedProviderTargets = append(expectedProviderTargets, providerTarget4) - - require := s.Require() - - err := s.providerTargetService.Save(providerTarget4) - require.Nil(err) - - providerTargets, err := s.providerTargetService.List(nil) - require.Nil(err) - require.ElementsMatch(expectedProviderTargets, providerTargets) -} - -func (s *ProviderTargetServiceTestSuite) TestDelete() { - expectedProviderTargets = expectedProviderTargets[:2] - - require := s.Require() - - err := s.providerTargetService.Delete(providerTarget3) - require.Nil(err) - - providerTargets, err := s.providerTargetService.List(nil) - require.Nil(err) - require.ElementsMatch(expectedProviderTargets, providerTargets) -} diff --git a/pkg/server/purge.go b/pkg/server/purge.go deleted file mode 100644 index cd292f368f..0000000000 --- a/pkg/server/purge.go +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package server - -import ( - "context" - "fmt" - "time" - - "github.com/daytonaio/daytona/pkg/telemetry" - log "github.com/sirupsen/logrus" -) - -func (s *Server) Purge(ctx context.Context, force bool) []error { - log.SetLevel(log.PanicLevel) - - telemetryEnabled := telemetry.TelemetryEnabled(ctx) - telemetryProps := map[string]interface{}{ - "force": force, - "server_id": s.Id, - } - - if telemetryEnabled { - err := s.TelemetryService.TrackServerEvent(telemetry.ServerEventPurgeStarted, telemetry.ClientId(ctx), telemetryProps) - if err != nil { - log.Trace(err) - } - } - - fmt.Println("Deleting all workspaces...") - - err := server.Start() - if err != nil { - s.trackPurgeError(ctx, force, err) - return []error{err} - } - - workspaces, err := s.WorkspaceService.ListWorkspaces(ctx, false) - if err != nil { - s.trackPurgeError(ctx, force, err) - if !force { - return []error{err} - } - } - - if err == nil { - for _, workspace := range workspaces { - err := s.WorkspaceService.RemoveWorkspace(ctx, workspace.Id) - if err != nil { - s.trackPurgeError(ctx, force, err) - if !force { - return []error{err} - } else { - fmt.Printf("Failed to delete %s: %v\n", workspace.Name, err) - } - } else { - fmt.Printf("Workspace %s deleted\n", workspace.Name) - } - } - } else { - fmt.Printf("Failed to list workspaces: %v\n", err) - } - - fmt.Println("Purging providers...") - err = s.ProviderManager.Purge() - if err != nil { - s.trackPurgeError(ctx, force, err) - if !force { - return []error{err} - } else { - fmt.Printf("Failed to purge providers: %v\n", err) - } - } - - fmt.Println("Purging builds...") - errs := s.BuildService.MarkForDeletion(nil, force) - if len(errs) > 0 { - s.trackPurgeError(ctx, force, errs[0]) - if !force { - return errs - } else { - fmt.Printf("Failed to mark builds for deletion: %v\n", errs[0]) - } - } - - err = s.BuildService.AwaitEmptyList(time.Minute) - if err != nil { - s.trackPurgeError(ctx, force, err) - if !force { - return []error{err} - } else { - fmt.Printf("Failed to await empty build list: %v\n", err) - } - } - - if telemetryEnabled { - err := s.TelemetryService.TrackServerEvent(telemetry.ServerEventPurgeCompleted, telemetry.ClientId(ctx), telemetryProps) - if err != nil { - log.Trace(err) - } - } - - return nil -} - -func (s *Server) trackPurgeError(ctx context.Context, force bool, err error) { - telemetryEnabled := telemetry.TelemetryEnabled(ctx) - telemetryProps := map[string]interface{}{ - "server_id": s.Id, - "force": force, - "error": err.Error(), - } - - if telemetryEnabled { - err := s.TelemetryService.TrackServerEvent(telemetry.ServerEventPurgeError, telemetry.ClientId(ctx), telemetryProps) - if err != nil { - log.Trace(err) - } - } -} diff --git a/pkg/server/registry/service.go b/pkg/server/registry/service.go index 9d6e819e72..723643790a 100644 --- a/pkg/server/registry/service.go +++ b/pkg/server/registry/service.go @@ -12,9 +12,9 @@ import ( "os" "time" - "github.com/daytonaio/daytona/pkg/containerregistry" "github.com/daytonaio/daytona/pkg/docker" "github.com/daytonaio/daytona/pkg/frpc" + "github.com/daytonaio/daytona/pkg/models" "github.com/daytonaio/daytona/pkg/server" "github.com/docker/docker/api/types/container" "github.com/docker/docker/client" @@ -29,7 +29,7 @@ type LocalContainerRegistryConfig struct { DataPath string Port uint32 Image string - ContainerRegistry *containerregistry.ContainerRegistry + ContainerRegistry *models.ContainerRegistry Logger io.Writer Frps *server.FRPSConfig ServerId string @@ -51,7 +51,7 @@ type LocalContainerRegistry struct { dataPath string port uint32 image string - containerRegistry *containerregistry.ContainerRegistry + containerRegistry *models.ContainerRegistry logger io.Writer frps *server.FRPSConfig serverId string @@ -85,7 +85,7 @@ func (s *LocalContainerRegistry) Start() error { // we want to always create a new container // to avoid conflicts with configuration changes - if err := RemoveRegistryContainer(); err != nil { + if err := DeleteRegistryContainer(); err != nil { return err } @@ -170,19 +170,14 @@ func (s *LocalContainerRegistry) Start() error { } func (s *LocalContainerRegistry) Stop() error { - return RemoveRegistryContainer() + return DeleteRegistryContainer() } func (s *LocalContainerRegistry) Purge() error { - err := s.Stop() - if err != nil { - return err - } - return os.RemoveAll(s.dataPath) } -func RemoveRegistryContainer() error { +func DeleteRegistryContainer() error { cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) if err != nil { return err diff --git a/pkg/server/runners/create.go b/pkg/server/runners/create.go new file mode 100644 index 0000000000..ee6d9766d9 --- /dev/null +++ b/pkg/server/runners/create.go @@ -0,0 +1,90 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package runners + +import ( + "context" + + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/services" + "github.com/daytonaio/daytona/pkg/stores" + "github.com/daytonaio/daytona/pkg/telemetry" + + log "github.com/sirupsen/logrus" +) + +func (s *RunnerService) Create(ctx context.Context, req services.CreateRunnerDTO) (*services.RunnerDTO, error) { + var err error + ctx, err = s.runnerStore.BeginTransaction(ctx) + if err != nil { + return nil, s.handleRegisterError(ctx, nil, err) + } + + defer stores.RecoverAndRollback(ctx, s.runnerStore) + + _, err = s.runnerStore.Find(ctx, req.Name) + if err == nil { + return nil, s.handleRegisterError(ctx, nil, services.ErrRunnerAlreadyExists) + } + + apiKey, err := s.createApiKey(ctx, req.Id) + if err != nil { + return nil, s.handleRegisterError(ctx, nil, err) + } + + runner := &models.Runner{ + Id: req.Id, + Name: req.Name, + ApiKey: apiKey, + Metadata: &models.RunnerMetadata{ + RunnerId: req.Id, + Uptime: 0, + }, + } + + err = s.runnerMetadataStore.Save(ctx, runner.Metadata) + if err != nil { + return nil, s.handleRegisterError(ctx, runner, err) + } + + err = s.runnerStore.Save(ctx, runner) + if err != nil { + return nil, s.handleRegisterError(ctx, runner, err) + } + + err = s.runnerStore.CommitTransaction(ctx) + if err != nil { + return nil, s.handleRegisterError(ctx, runner, err) + } + + return &services.RunnerDTO{ + Runner: *runner, + State: runner.GetState(), + }, s.handleRegisterError(ctx, runner, nil) +} + +func (s *RunnerService) handleRegisterError(ctx context.Context, r *models.Runner, err error) error { + if err != nil { + err = s.runnerStore.RollbackTransaction(ctx, err) + } + + if !telemetry.TelemetryEnabled(ctx) { + return err + } + + clientId := telemetry.ClientId(ctx) + + eventName := telemetry.RunnerEventLifecycleRegistered + if err != nil { + eventName = telemetry.RunnerEventLifecycleRegistrationFailed + } + event := telemetry.NewRunnerEvent(eventName, r, err, nil) + + telemetryError := s.trackTelemetryEvent(event, clientId) + if telemetryError != nil { + log.Trace(telemetryError) + } + + return err +} diff --git a/pkg/server/runners/delete.go b/pkg/server/runners/delete.go new file mode 100644 index 0000000000..f752f41e7e --- /dev/null +++ b/pkg/server/runners/delete.go @@ -0,0 +1,82 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package runners + +import ( + "context" + + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/stores" + "github.com/daytonaio/daytona/pkg/telemetry" + log "github.com/sirupsen/logrus" +) + +func (s *RunnerService) Delete(ctx context.Context, runnerId string) error { + var err error + ctx, err = s.runnerStore.BeginTransaction(ctx) + if err != nil { + return s.handleDeleteError(ctx, nil, err) + } + + defer stores.RecoverAndRollback(ctx, s.runnerStore) + + runner, err := s.runnerStore.Find(ctx, runnerId) + if err != nil { + return s.handleDeleteError(ctx, nil, err) + } + + err = s.runnerStore.Delete(ctx, runner) + if err != nil { + return s.handleDeleteError(ctx, runner, err) + } + + metadata, err := s.runnerMetadataStore.Find(ctx, runnerId) + if err != nil && !stores.IsRunnerMetadataNotFound(err) { + return s.handleDeleteError(ctx, runner, err) + } + if metadata != nil { + err = s.runnerMetadataStore.Delete(ctx, metadata) + if err != nil { + return s.handleDeleteError(ctx, runner, err) + } + } + + err = s.deleteApiKey(ctx, runner.Id) + if err != nil { + return s.handleDeleteError(ctx, runner, err) + } + + err = s.unsetDefaultTarget(ctx, runner.Id) + if err != nil { + return s.handleDeleteError(ctx, runner, err) + } + + err = s.runnerStore.CommitTransaction(ctx) + return s.handleDeleteError(ctx, runner, err) +} + +func (s *RunnerService) handleDeleteError(ctx context.Context, r *models.Runner, err error) error { + if err != nil { + err = s.runnerStore.RollbackTransaction(ctx, err) + } + + if !telemetry.TelemetryEnabled(ctx) { + return err + } + + clientId := telemetry.ClientId(ctx) + + eventName := telemetry.RunnerEventLifecycleDeleted + if err != nil { + eventName = telemetry.RunnerEventLifecycleDeletionFailed + } + event := telemetry.NewRunnerEvent(eventName, r, err, nil) + + telemetryError := s.trackTelemetryEvent(event, clientId) + if telemetryError != nil { + log.Trace(telemetryError) + } + + return err +} diff --git a/pkg/server/runners/jobs.go b/pkg/server/runners/jobs.go new file mode 100644 index 0000000000..573090b1dd --- /dev/null +++ b/pkg/server/runners/jobs.go @@ -0,0 +1,19 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package runners + +import ( + "context" + + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/services" +) + +func (s *RunnerService) ListRunnerJobs(ctx context.Context, runnerId string) ([]*models.Job, error) { + return s.listJobsForRunner(ctx, runnerId) +} + +func (s *RunnerService) UpdateJobState(ctx context.Context, jobId string, req services.UpdateJobStateDTO) error { + return s.updateJobState(ctx, jobId, req) +} diff --git a/pkg/server/runners/provider.go b/pkg/server/runners/provider.go new file mode 100644 index 0000000000..3c76e2b786 --- /dev/null +++ b/pkg/server/runners/provider.go @@ -0,0 +1,171 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package runners + +import ( + "context" + "encoding/json" + + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/runner" + "github.com/daytonaio/daytona/pkg/services" + "github.com/daytonaio/daytona/pkg/telemetry" + log "github.com/sirupsen/logrus" +) + +func (s *RunnerService) ListProviders(ctx context.Context, runnerId *string) ([]models.ProviderInfo, error) { + var metadatas []*models.RunnerMetadata + + if runnerId == nil { + var err error + metadatas, err = s.runnerMetadataStore.List(ctx) + if err != nil { + return nil, err + } + } else { + metadata, err := s.runnerMetadataStore.Find(ctx, *runnerId) + if err != nil { + return nil, err + } + metadatas = []*models.RunnerMetadata{metadata} + } + + providers := []models.ProviderInfo{} + for _, metadata := range metadatas { + providers = append(providers, metadata.Providers...) + } + + return providers, nil +} + +func (s *RunnerService) ListProvidersForInstall(ctx context.Context, registryUrl string) ([]services.ProviderDTO, error) { + providersManifest, err := runner.GetProvidersManifest(registryUrl) + if err != nil { + return nil, err + } + + return providersManifest.GetProviderListFromManifest(), nil +} + +func (s *RunnerService) InstallProvider(ctx context.Context, runnerId, name, version, registryUrl string) error { + params := providerActionParams{ + providerName: name, + providerVersion: &version, + eventName: telemetry.RunnerEventProviderInstalled, + errEventName: telemetry.RunnerEventProviderInstallationFailed, + } + + downloadUrls, err := runner.GetProviderDownloadUrls(name, version, registryUrl) + if err != nil { + return s.handleProviderActionError(ctx, params, err) + } + + runner, err := s.runnerStore.Find(ctx, runnerId) + if err != nil { + return s.handleProviderActionError(ctx, params, err) + } + + params.runner = runner + + metadata, err := json.Marshal(services.ProviderMetadata{ + Name: name, + Version: version, + DownloadUrls: downloadUrls, + }) + if err != nil { + return s.handleProviderActionError(ctx, params, err) + } + + err = s.createJob(ctx, runnerId, models.JobActionInstallProvider, string(metadata)) + return s.handleProviderActionError(ctx, params, err) +} + +func (s *RunnerService) UninstallProvider(ctx context.Context, runnerId string, providerName string) error { + params := providerActionParams{ + providerName: providerName, + eventName: telemetry.RunnerEventProviderUninstalled, + errEventName: telemetry.RunnerEventProviderUninstallationFailed, + } + + runner, err := s.runnerStore.Find(ctx, runnerId) + if err != nil { + return s.handleProviderActionError(ctx, params, err) + } + + params.runner = runner + + err = s.createJob(ctx, runnerId, models.JobActionUninstallProvider, providerName) + return s.handleProviderActionError(ctx, params, err) +} + +func (s *RunnerService) UpdateProvider(ctx context.Context, runnerId, name, version, registryUrl string) error { + params := providerActionParams{ + providerName: name, + providerVersion: &version, + eventName: telemetry.RunnerEventProviderUpdated, + errEventName: telemetry.RunnerEventProviderUpdateFailed, + } + + r, err := s.runnerStore.Find(ctx, runnerId) + if err != nil { + return s.handleProviderActionError(ctx, params, err) + } + + params.runner = r + + downloadUrls, err := runner.GetProviderDownloadUrls(name, version, registryUrl) + if err != nil { + return s.handleProviderActionError(ctx, params, err) + } + + providerDto := services.ProviderMetadata{ + DownloadUrls: downloadUrls, + Version: version, + Name: name, + } + + metadata, err := json.Marshal(providerDto) + if err != nil { + return s.handleProviderActionError(ctx, params, err) + } + + err = s.createJob(ctx, r.Id, models.JobActionUpdateProvider, string(metadata)) + return s.handleProviderActionError(ctx, params, err) +} + +type providerActionParams struct { + runner *models.Runner + eventName telemetry.RunnerEventName + errEventName telemetry.RunnerEventName + providerName string + providerVersion *string +} + +func (s *RunnerService) handleProviderActionError(ctx context.Context, params providerActionParams, err error) error { + if !telemetry.TelemetryEnabled(ctx) { + return err + } + + eventName := params.eventName + if err != nil { + eventName = params.errEventName + } + + clientId := telemetry.ClientId(ctx) + + extras := map[string]interface{}{ + "provider_name": params.providerName, + } + if params.providerVersion != nil { + extras["provider_version"] = *params.providerVersion + } + + event := telemetry.NewRunnerEvent(eventName, params.runner, err, extras) + telemetryError := s.trackTelemetryEvent(event, clientId) + if telemetryError != nil { + log.Trace(telemetryError) + } + + return err +} diff --git a/pkg/server/runners/service.go b/pkg/server/runners/service.go new file mode 100644 index 0000000000..7b8f499d82 --- /dev/null +++ b/pkg/server/runners/service.go @@ -0,0 +1,110 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package runners + +import ( + "context" + "io" + + "github.com/daytonaio/daytona/internal/util" + "github.com/daytonaio/daytona/pkg/logs" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/services" + "github.com/daytonaio/daytona/pkg/stores" + "github.com/daytonaio/daytona/pkg/telemetry" +) + +type RunnerServiceConfig struct { + RunnerStore stores.RunnerStore + RunnerMetadataStore stores.RunnerMetadataStore + LoggerFactory logs.ILoggerFactory + + CreateJob func(ctx context.Context, runnerId string, action models.JobAction, metadata string) error + ListJobsForRunner func(ctx context.Context, runnerId string) ([]*models.Job, error) + UpdateJobState func(ctx context.Context, jobId string, updateJobStateDto services.UpdateJobStateDTO) error + CreateApiKey func(ctx context.Context, name string) (string, error) + DeleteApiKey func(ctx context.Context, name string) error + UnsetDefaultTarget func(ctx context.Context, runnerId string) error + + TrackTelemetryEvent func(event telemetry.Event, clientId string) error +} + +func NewRunnerService(config RunnerServiceConfig) services.IRunnerService { + return &RunnerService{ + runnerStore: config.RunnerStore, + runnerMetadataStore: config.RunnerMetadataStore, + loggerFactory: config.LoggerFactory, + + createJob: config.CreateJob, + listJobsForRunner: config.ListJobsForRunner, + updateJobState: config.UpdateJobState, + createApiKey: config.CreateApiKey, + deleteApiKey: config.DeleteApiKey, + unsetDefaultTarget: config.UnsetDefaultTarget, + + trackTelemetryEvent: config.TrackTelemetryEvent, + } +} + +type RunnerService struct { + runnerStore stores.RunnerStore + runnerMetadataStore stores.RunnerMetadataStore + loggerFactory logs.ILoggerFactory + + createJob func(ctx context.Context, runnerId string, action models.JobAction, metadata string) error + listJobsForRunner func(ctx context.Context, runnerId string) ([]*models.Job, error) + updateJobState func(ctx context.Context, jobId string, updateJobStateDto services.UpdateJobStateDTO) error + createApiKey func(ctx context.Context, name string) (string, error) + deleteApiKey func(ctx context.Context, name string) error + unsetDefaultTarget func(ctx context.Context, runnerId string) error + + trackTelemetryEvent func(event telemetry.Event, clientId string) error +} + +func (s *RunnerService) Find(ctx context.Context, runnerId string) (*services.RunnerDTO, error) { + runner, err := s.runnerStore.Find(ctx, runnerId) + if err != nil { + return nil, stores.ErrRunnerNotFound + } + + return &services.RunnerDTO{ + Runner: *runner, + State: runner.GetState(), + }, nil +} + +func (s *RunnerService) List(ctx context.Context) ([]*services.RunnerDTO, error) { + runners, err := s.runnerStore.List(ctx) + if err != nil { + return nil, err + } + + return util.ArrayMap(runners, func(runner *models.Runner) *services.RunnerDTO { + return &services.RunnerDTO{ + Runner: *runner, + State: runner.GetState(), + } + }), nil +} + +func (s *RunnerService) UpdateMetadata(ctx context.Context, runnerId string, metadata *models.RunnerMetadata) error { + m, err := s.runnerMetadataStore.Find(ctx, runnerId) + if err != nil { + return stores.ErrRunnerMetadataNotFound + } + + m.Uptime = metadata.Uptime + m.RunningJobs = metadata.RunningJobs + m.Providers = metadata.Providers + m.UpdatedAt = metadata.UpdatedAt + return s.runnerMetadataStore.Save(ctx, m) +} + +func (s *RunnerService) GetRunnerLogReader(ctx context.Context, runnerId string) (io.Reader, error) { + return s.loggerFactory.CreateLogReader(runnerId) +} + +func (s *RunnerService) GetRunnerLogWriter(ctx context.Context, runnerId string) (io.WriteCloser, error) { + return s.loggerFactory.CreateLogWriter(runnerId) +} diff --git a/pkg/server/server.go b/pkg/server/server.go index 5c960cb05f..d341bbc596 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -4,39 +4,28 @@ package server import ( - "os" - "os/signal" - - "github.com/daytonaio/daytona/pkg/provider/manager" - "github.com/daytonaio/daytona/pkg/server/apikeys" - "github.com/daytonaio/daytona/pkg/server/builds" - "github.com/daytonaio/daytona/pkg/server/containerregistries" - "github.com/daytonaio/daytona/pkg/server/gitproviders" - "github.com/daytonaio/daytona/pkg/server/profiledata" - "github.com/daytonaio/daytona/pkg/server/projectconfig" - "github.com/daytonaio/daytona/pkg/server/providertargets" - "github.com/daytonaio/daytona/pkg/server/workspaces" + "github.com/daytonaio/daytona/pkg/services" "github.com/daytonaio/daytona/pkg/telemetry" - "github.com/hashicorp/go-plugin" log "github.com/sirupsen/logrus" ) type ServerInstanceConfig struct { - Config Config - Version string - TailscaleServer TailscaleServer - ProviderTargetService providertargets.IProviderTargetService - ContainerRegistryService containerregistries.IContainerRegistryService - BuildService builds.IBuildService - ProjectConfigService projectconfig.IProjectConfigService - LocalContainerRegistry ILocalContainerRegistry - WorkspaceService workspaces.IWorkspaceService - ApiKeyService apikeys.IApiKeyService - GitProviderService gitproviders.IGitProviderService - ProviderManager manager.IProviderManager - ProfileDataService profiledata.IProfileDataService - TelemetryService telemetry.TelemetryService + Config Config + Version string + TailscaleServer TailscaleServer + TargetConfigService services.ITargetConfigService + BuildService services.IBuildService + WorkspaceTemplateService services.IWorkspaceTemplateService + WorkspaceService services.IWorkspaceService + LocalContainerRegistry ILocalContainerRegistry + TargetService services.ITargetService + ApiKeyService services.IApiKeyService + GitProviderService services.IGitProviderService + EnvironmentVariableService services.IEnvironmentVariableService + JobService services.IJobService + RunnerService services.IRunnerService + TelemetryService telemetry.TelemetryService } var server *Server @@ -51,21 +40,22 @@ func GetInstance(serverConfig *ServerInstanceConfig) *Server { log.Fatal("Server not initialized") } server = &Server{ - Id: serverConfig.Config.Id, - config: serverConfig.Config, - Version: serverConfig.Version, - TailscaleServer: serverConfig.TailscaleServer, - ProviderTargetService: serverConfig.ProviderTargetService, - ContainerRegistryService: serverConfig.ContainerRegistryService, - BuildService: serverConfig.BuildService, - ProjectConfigService: serverConfig.ProjectConfigService, - LocalContainerRegistry: serverConfig.LocalContainerRegistry, - WorkspaceService: serverConfig.WorkspaceService, - ApiKeyService: serverConfig.ApiKeyService, - GitProviderService: serverConfig.GitProviderService, - ProviderManager: serverConfig.ProviderManager, - ProfileDataService: serverConfig.ProfileDataService, - TelemetryService: serverConfig.TelemetryService, + Id: serverConfig.Config.Id, + config: serverConfig.Config, + Version: serverConfig.Version, + TailscaleServer: serverConfig.TailscaleServer, + TargetConfigService: serverConfig.TargetConfigService, + BuildService: serverConfig.BuildService, + WorkspaceTemplateService: serverConfig.WorkspaceTemplateService, + WorkspaceService: serverConfig.WorkspaceService, + LocalContainerRegistry: serverConfig.LocalContainerRegistry, + TargetService: serverConfig.TargetService, + ApiKeyService: serverConfig.ApiKeyService, + GitProviderService: serverConfig.GitProviderService, + EnvironmentVariableService: serverConfig.EnvironmentVariableService, + JobService: serverConfig.JobService, + RunnerService: serverConfig.RunnerService, + TelemetryService: serverConfig.TelemetryService, } } @@ -73,49 +63,24 @@ func GetInstance(serverConfig *ServerInstanceConfig) *Server { } type Server struct { - Id string - config Config - Version string - TailscaleServer TailscaleServer - ProviderTargetService providertargets.IProviderTargetService - ContainerRegistryService containerregistries.IContainerRegistryService - BuildService builds.IBuildService - ProjectConfigService projectconfig.IProjectConfigService - LocalContainerRegistry ILocalContainerRegistry - WorkspaceService workspaces.IWorkspaceService - ApiKeyService apikeys.IApiKeyService - GitProviderService gitproviders.IGitProviderService - ProviderManager manager.IProviderManager - ProfileDataService profiledata.IProfileDataService - TelemetryService telemetry.TelemetryService + Id string + config Config + Version string + TailscaleServer TailscaleServer + TargetConfigService services.ITargetConfigService + BuildService services.IBuildService + WorkspaceTemplateService services.IWorkspaceTemplateService + WorkspaceService services.IWorkspaceService + LocalContainerRegistry ILocalContainerRegistry + TargetService services.ITargetService + ApiKeyService services.IApiKeyService + GitProviderService services.IGitProviderService + EnvironmentVariableService services.IEnvironmentVariableService + JobService services.IJobService + RunnerService services.IRunnerService + TelemetryService telemetry.TelemetryService } func (s *Server) Initialize() error { return s.initLogs() } - -func (s *Server) Start() error { - log.Info("Starting Daytona server") - - go func() { - interruptChannel := make(chan os.Signal, 1) - signal.Notify(interruptChannel, os.Interrupt) - - for range interruptChannel { - plugin.CleanupClients() - } - }() - - // Terminate orphaned provider processes - err := s.ProviderManager.TerminateProviderProcesses(s.config.ProvidersDir) - if err != nil { - log.Errorf("Failed to terminate orphaned provider processes: %s", err) - } - - err = s.downloadDefaultProviders() - if err != nil { - return err - } - - return s.registerProviders() -} diff --git a/pkg/server/targetconfigs/service.go b/pkg/server/targetconfigs/service.go new file mode 100644 index 0000000000..3e78e5b216 --- /dev/null +++ b/pkg/server/targetconfigs/service.go @@ -0,0 +1,129 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package targetconfigs + +import ( + "context" + + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/services" + "github.com/daytonaio/daytona/pkg/stores" + "github.com/daytonaio/daytona/pkg/telemetry" + "github.com/docker/docker/pkg/stringid" + + log "github.com/sirupsen/logrus" +) + +type TargetConfigServiceConfig struct { + TargetConfigStore stores.TargetConfigStore + TrackTelemetryEvent func(event telemetry.Event, clientId string) error +} + +type TargetConfigService struct { + targetConfigStore stores.TargetConfigStore + trackTelemetryEvent func(event telemetry.Event, clientId string) error +} + +func NewTargetConfigService(config TargetConfigServiceConfig) services.ITargetConfigService { + return &TargetConfigService{ + targetConfigStore: config.TargetConfigStore, + trackTelemetryEvent: config.TrackTelemetryEvent, + } +} + +func (s *TargetConfigService) List(ctx context.Context) ([]*models.TargetConfig, error) { + return s.targetConfigStore.List(ctx, false) +} + +func (s *TargetConfigService) Map(ctx context.Context) (map[string]*models.TargetConfig, error) { + list, err := s.targetConfigStore.List(ctx, false) + if err != nil { + return nil, err + } + + targetConfigs := make(map[string]*models.TargetConfig) + for _, targetConfig := range list { + targetConfigs[targetConfig.Name] = targetConfig + } + + return targetConfigs, nil +} + +func (s *TargetConfigService) Find(ctx context.Context, idOrName string) (*models.TargetConfig, error) { + return s.targetConfigStore.Find(ctx, idOrName, false) +} + +func (s *TargetConfigService) Create(ctx context.Context, addTargetConfig services.CreateTargetConfigDTO) (*models.TargetConfig, error) { + persistedTargetConfig, err := s.targetConfigStore.Find(ctx, addTargetConfig.Name, false) + if err != nil && !stores.IsTargetConfigNotFound(err) { + return nil, s.handleCreateError(ctx, nil, err) + } + if persistedTargetConfig != nil && !persistedTargetConfig.Deleted { + return nil, s.handleCreateError(ctx, nil, stores.ErrTargetConfigAlreadyExists) + } + + targetConfig := &models.TargetConfig{ + Id: stringid.GenerateRandomID(), + Name: addTargetConfig.Name, + ProviderInfo: addTargetConfig.ProviderInfo, + Options: addTargetConfig.Options, + Deleted: false, + } + + err = s.targetConfigStore.Save(ctx, targetConfig) + return targetConfig, s.handleCreateError(ctx, targetConfig, err) +} + +func (s *TargetConfigService) Delete(ctx context.Context, targetConfigId string) error { + targetConfig, err := s.targetConfigStore.Find(ctx, targetConfigId, false) + if err != nil { + return s.handleDeleteError(ctx, nil, err) + } + targetConfig.Deleted = true + + err = s.targetConfigStore.Save(ctx, targetConfig) + return s.handleDeleteError(ctx, targetConfig, err) +} + +func (s *TargetConfigService) handleCreateError(ctx context.Context, tc *models.TargetConfig, err error) error { + if !telemetry.TelemetryEnabled(ctx) { + return err + } + + clientId := telemetry.ClientId(ctx) + + eventName := telemetry.TargetConfigEventLifecycleCreated + if err != nil { + eventName = telemetry.TargetConfigEventLifecycleCreationFailed + } + event := telemetry.NewTargetConfigEvent(eventName, tc, err, nil) + + telemetryError := s.trackTelemetryEvent(event, clientId) + if telemetryError != nil { + log.Trace(telemetryError) + } + + return err +} + +func (s *TargetConfigService) handleDeleteError(ctx context.Context, tc *models.TargetConfig, err error) error { + if !telemetry.TelemetryEnabled(ctx) { + return err + } + + clientId := telemetry.ClientId(ctx) + + eventName := telemetry.TargetConfigEventLifecycleDeleted + if err != nil { + eventName = telemetry.TargetConfigEventLifecycleDeletionFailed + } + event := telemetry.NewTargetConfigEvent(eventName, tc, err, nil) + + telemetryError := s.trackTelemetryEvent(event, clientId) + if telemetryError != nil { + log.Trace(telemetryError) + } + + return err +} diff --git a/pkg/server/targetconfigs/service_test.go b/pkg/server/targetconfigs/service_test.go new file mode 100644 index 0000000000..108a5ee3d0 --- /dev/null +++ b/pkg/server/targetconfigs/service_test.go @@ -0,0 +1,154 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package targetconfigs_test + +import ( + "context" + "testing" + + t_targetconfigs "github.com/daytonaio/daytona/internal/testing/server/targetconfigs" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/server/targetconfigs" + "github.com/daytonaio/daytona/pkg/services" + "github.com/daytonaio/daytona/pkg/stores" + "github.com/stretchr/testify/suite" +) + +var targetConfig1 *models.TargetConfig = &models.TargetConfig{ + Name: "targetConfig1", + ProviderInfo: models.ProviderInfo{ + Name: "provider1", + Version: "v1", + }, + Options: "", +} + +var targetConfig2 *models.TargetConfig = &models.TargetConfig{ + Name: "targetConfig2", + ProviderInfo: models.ProviderInfo{ + Name: "provider2", + Version: "v1", + }, + Options: "", +} + +var targetConfig3 *models.TargetConfig = &models.TargetConfig{ + Name: "targetConfig3", + ProviderInfo: models.ProviderInfo{ + Name: "provider3", + Version: "v1", + }, + Options: "", +} + +var targetConfig4 *models.TargetConfig = &models.TargetConfig{ + Name: "newTargetConfig", + ProviderInfo: models.ProviderInfo{ + Name: "provider2", + Version: "v1", + }, + Options: "", +} + +var expectedConfigs []*models.TargetConfig +var expectedConfigMap map[string]*models.TargetConfig + +type TargetConfigServiceTestSuite struct { + suite.Suite + targetConfigService services.ITargetConfigService + targetConfigStore stores.TargetConfigStore +} + +func NewTargetConfigServiceTestSuite() *TargetConfigServiceTestSuite { + return &TargetConfigServiceTestSuite{} +} + +func (s *TargetConfigServiceTestSuite) SetupTest() { + expectedConfigs = []*models.TargetConfig{ + targetConfig1, targetConfig2, targetConfig3, + } + + expectedConfigMap = map[string]*models.TargetConfig{ + targetConfig1.Name: targetConfig1, + targetConfig2.Name: targetConfig2, + targetConfig3.Name: targetConfig3, + } + + s.targetConfigStore = t_targetconfigs.NewInMemoryTargetConfigStore() + s.targetConfigService = targetconfigs.NewTargetConfigService(targetconfigs.TargetConfigServiceConfig{ + TargetConfigStore: s.targetConfigStore, + }) + + for _, targetConfig := range expectedConfigs { + tc, err := s.targetConfigService.Create(context.TODO(), services.CreateTargetConfigDTO{ + Name: targetConfig.Name, + ProviderInfo: targetConfig.ProviderInfo, + Options: targetConfig.Options, + }) + if err != nil { + panic(err) + } + targetConfig.Id = tc.Id + } +} + +func TestTargetConfigService(t *testing.T) { + suite.Run(t, NewTargetConfigServiceTestSuite()) +} + +func (s *TargetConfigServiceTestSuite) TestList() { + require := s.Require() + + targetConfigs, err := s.targetConfigService.List(context.TODO()) + require.Nil(err) + require.ElementsMatch(expectedConfigs, targetConfigs) +} + +func (s *TargetConfigServiceTestSuite) TestMap() { + require := s.Require() + + targetConfigsMap, err := s.targetConfigService.Map(context.TODO()) + require.Nil(err) + require.Equal(expectedConfigMap, targetConfigsMap) +} + +func (s *TargetConfigServiceTestSuite) TestFind() { + require := s.Require() + + targetConfig, err := s.targetConfigService.Find(context.TODO(), targetConfig1.Id) + require.Nil(err) + require.Equal(targetConfig1, targetConfig) +} + +func (s *TargetConfigServiceTestSuite) TestSave() { + require := s.Require() + + tc, err := s.targetConfigService.Create(context.TODO(), services.CreateTargetConfigDTO{ + Name: targetConfig4.Name, + ProviderInfo: targetConfig4.ProviderInfo, + Options: targetConfig4.Options, + }) + require.Nil(err) + + targetConfig4.Id = tc.Id + expectedConfigs = append(expectedConfigs, targetConfig4) + + targetConfigs, err := s.targetConfigService.List(context.TODO()) + require.Nil(err) + require.ElementsMatch(expectedConfigs, targetConfigs) +} + +func (s *TargetConfigServiceTestSuite) TestDelete() { + expected := expectedConfigs[:2] + + require := s.Require() + + err := s.targetConfigService.Delete(context.TODO(), targetConfig3.Id) + require.Nil(err) + + targetConfigs, err := s.targetConfigService.List(context.TODO()) + require.Nil(err) + + require.ElementsMatch(expected, targetConfigs) +} diff --git a/pkg/server/targets/create.go b/pkg/server/targets/create.go new file mode 100644 index 0000000000..d22d17c5e1 --- /dev/null +++ b/pkg/server/targets/create.go @@ -0,0 +1,130 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package targets + +import ( + "context" + "regexp" + + "github.com/daytonaio/daytona/internal/util" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/services" + "github.com/daytonaio/daytona/pkg/stores" + "github.com/daytonaio/daytona/pkg/telemetry" + + log "github.com/sirupsen/logrus" +) + +func (s *TargetService) Create(ctx context.Context, req services.CreateTargetDTO) (*models.Target, error) { + var err error + ctx, err = s.targetStore.BeginTransaction(ctx) + if err != nil { + return s.handleCreateError(ctx, nil, err) + } + + defer stores.RecoverAndRollback(ctx, s.targetStore) + + _, err = s.targetStore.Find(ctx, &stores.TargetFilter{IdOrName: &req.Id}) + if err == nil { + return nil, services.ErrTargetAlreadyExists + } + + tc, err := s.findTargetConfig(ctx, req.TargetConfigId) + if err != nil { + return s.handleCreateError(ctx, nil, err) + } + + // Repo name is taken as the name for target by default + if !isValidTargetName(req.Name) { + return s.handleCreateError(ctx, nil, services.ErrInvalidTargetName) + } + + tg := &models.Target{ + Id: req.Id, + Name: req.Name, + TargetConfigId: tc.Id, + TargetConfig: *tc, + } + + apiKey, err := s.createApiKey(ctx, tg.Id) + if err != nil { + return s.handleCreateError(ctx, nil, err) + } + tg.ApiKey = apiKey + + err = s.targetMetadataStore.Save(ctx, &models.TargetMetadata{ + TargetId: tg.Id, + Uptime: 0, + }) + if err != nil { + return s.handleCreateError(ctx, tg, err) + } + + daytonaTargetEnvVars := GetTargetEnvVars(tg, TargetEnvVarParams{ + ApiUrl: s.serverApiUrl, + ServerUrl: s.serverUrl, + ServerVersion: s.serverVersion, + ClientId: telemetry.ClientId(ctx), + TelemetryEnabled: telemetry.TelemetryEnabled(ctx), + }) + tg.EnvVars = util.MergeEnvVars(daytonaTargetEnvVars, tg.EnvVars) + + err = s.targetStore.Save(ctx, tg) + if err != nil { + return s.handleCreateError(ctx, nil, err) + } + + err = s.createJob(ctx, tg.Id, tg.TargetConfig.ProviderInfo.RunnerId, models.JobActionCreate) + if err != nil { + return s.handleCreateError(ctx, tg, err) + } + + err = s.targetStore.CommitTransaction(ctx) + return s.handleCreateError(ctx, tg, err) +} + +func (s *TargetService) HandleSuccessfulCreation(ctx context.Context, targetId string) error { + return s.SetDefault(ctx, targetId) +} + +func (s *TargetService) handleCreateError(ctx context.Context, target *models.Target, err error) (*models.Target, error) { + if err != nil { + err = s.targetStore.RollbackTransaction(ctx, err) + } + + if !telemetry.TelemetryEnabled(ctx) { + return target, err + } + + clientId := telemetry.ClientId(ctx) + + eventName := telemetry.TargetEventLifecycleCreated + if err != nil { + eventName = telemetry.TargetEventLifecycleCreationFailed + } + event := telemetry.NewTargetEvent(eventName, target, err, nil) + telemetryError := s.trackTelemetryEvent(event, clientId) + if telemetryError != nil { + log.Trace(telemetryError) + } + + return target, err +} + +func isValidTargetName(name string) bool { + // The repository name can only contain ASCII letters, digits, and the characters ., -, and _. + var validName = regexp.MustCompile(`^[a-zA-Z0-9._-]+$`) + + // Check if the name matches the basic regex + if !validName.MatchString(name) { + return false + } + + // Names starting with a period must have atleast one char appended to it. + if name == "." || name == "" { + return false + } + + return true +} diff --git a/pkg/server/targets/delete.go b/pkg/server/targets/delete.go new file mode 100644 index 0000000000..199a8458df --- /dev/null +++ b/pkg/server/targets/delete.go @@ -0,0 +1,151 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package targets + +import ( + "context" + + "github.com/daytonaio/daytona/internal/util" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/stores" + "github.com/daytonaio/daytona/pkg/telemetry" + log "github.com/sirupsen/logrus" +) + +func (s *TargetService) Delete(ctx context.Context, targetId string) error { + var err error + ctx, err = s.targetStore.BeginTransaction(ctx) + if err != nil { + return s.handleDeleteError(ctx, nil, err) + } + + defer stores.RecoverAndRollback(ctx, s.targetStore) + + t, err := s.targetStore.Find(ctx, &stores.TargetFilter{IdOrName: &targetId}) + if err != nil { + return s.handleDeleteError(ctx, t, stores.ErrTargetNotFound) + } + + t.Name = util.AddDeletedToName(t.Name) + t.IsDefault = false + + err = s.targetStore.Save(ctx, t) + if err != nil { + return s.handleDeleteError(ctx, t, err) + } + + err = s.deleteApiKey(ctx, targetId) + if err != nil { + return s.handleDeleteError(ctx, t, err) + } + + metadata, err := s.targetMetadataStore.Find(ctx, targetId) + if err == nil { + err = s.targetMetadataStore.Delete(ctx, metadata) + if err != nil { + return s.handleDeleteError(ctx, t, err) + } + } + + err = s.createJob(ctx, t.Id, t.TargetConfig.ProviderInfo.RunnerId, models.JobActionDelete) + if err != nil { + return s.handleDeleteError(ctx, t, err) + } + + err = s.targetStore.CommitTransaction(ctx) + return s.handleDeleteError(ctx, t, err) +} + +// ForceDelete ignores provider errors and makes sure the target is deleted from storage. +func (s *TargetService) ForceDelete(ctx context.Context, targetId string) error { + var err error + ctx, err = s.targetStore.BeginTransaction(ctx) + if err != nil { + return s.handleForceDeleteError(ctx, nil, err) + } + + defer stores.RecoverAndRollback(ctx, s.targetStore) + + t, err := s.targetStore.Find(ctx, &stores.TargetFilter{IdOrName: &targetId}) + if err != nil { + return s.handleForceDeleteError(ctx, nil, stores.ErrTargetNotFound) + } + + t.Name = util.AddDeletedToName(t.Name) + + err = s.targetStore.Save(ctx, t) + if err != nil { + return s.handleForceDeleteError(ctx, t, err) + } + + err = s.deleteApiKey(ctx, targetId) + if err != nil { + log.Error(err) + } + + metadata, err := s.targetMetadataStore.Find(ctx, targetId) + if err == nil { + err = s.targetMetadataStore.Delete(ctx, metadata) + if err != nil { + log.Error(err) + } + } + + err = s.createJob(ctx, t.Id, t.TargetConfig.ProviderInfo.RunnerId, models.JobActionForceDelete) + if err != nil { + return s.handleForceDeleteError(ctx, t, err) + } + + err = s.targetStore.CommitTransaction(ctx) + return s.handleForceDeleteError(ctx, t, err) +} + +func (s *TargetService) handleDeleteError(ctx context.Context, target *models.Target, err error) error { + if err != nil { + err = s.targetStore.RollbackTransaction(ctx, err) + } + + if !telemetry.TelemetryEnabled(ctx) { + return err + } + + clientId := telemetry.ClientId(ctx) + + eventName := telemetry.TargetEventLifecycleDeleted + if err != nil { + eventName = telemetry.TargetEventLifecycleDeletionFailed + } + event := telemetry.NewTargetEvent(eventName, target, err, nil) + telemetryError := s.trackTelemetryEvent(event, clientId) + if telemetryError != nil { + log.Trace(telemetryError) + } + + return err +} + +func (s *TargetService) handleForceDeleteError(ctx context.Context, target *models.Target, err error) error { + if err != nil { + err = s.targetStore.RollbackTransaction(ctx, err) + } + + if !telemetry.TelemetryEnabled(ctx) { + return err + } + + clientId := telemetry.ClientId(ctx) + + eventName := telemetry.TargetEventLifecycleForceDeleted + if err != nil { + eventName = telemetry.TargetEventLifecycleForceDeletionFailed + } + event := telemetry.NewTargetEvent(eventName, target, err, nil) + + telemetryError := s.trackTelemetryEvent(event, clientId) + if telemetryError != nil { + log.Trace(telemetryError) + } + + return err +} diff --git a/pkg/server/targets/env_vars.go b/pkg/server/targets/env_vars.go new file mode 100644 index 0000000000..3c868642f6 --- /dev/null +++ b/pkg/server/targets/env_vars.go @@ -0,0 +1,33 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package targets + +import "github.com/daytonaio/daytona/pkg/models" + +type TargetEnvVarParams struct { + ApiUrl string + ServerUrl string + ServerVersion string + ClientId string + TelemetryEnabled bool +} + +func GetTargetEnvVars(target *models.Target, params TargetEnvVarParams) map[string]string { + envVars := map[string]string{ + "DAYTONA_TARGET_ID": target.Id, + "DAYTONA_SERVER_API_KEY": target.ApiKey, + "DAYTONA_SERVER_VERSION": params.ServerVersion, + "DAYTONA_SERVER_URL": params.ServerUrl, + "DAYTONA_SERVER_API_URL": params.ApiUrl, + "DAYTONA_CLIENT_ID": params.ClientId, + // (HOME) will be replaced at runtime + "DAYTONA_AGENT_LOG_FILE_PATH": "(HOME)/.daytona-agent.log", + } + + if params.TelemetryEnabled { + envVars["DAYTONA_TELEMETRY_ENABLED"] = "true" + } + + return envVars +} diff --git a/pkg/server/targets/find.go b/pkg/server/targets/find.go new file mode 100644 index 0000000000..afdc619e01 --- /dev/null +++ b/pkg/server/targets/find.go @@ -0,0 +1,39 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package targets + +import ( + "context" + + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/services" + "github.com/daytonaio/daytona/pkg/stores" +) + +func (s *TargetService) Find(ctx context.Context, filter *stores.TargetFilter, params services.TargetRetrievalParams) (*services.TargetDTO, error) { + tg, err := s.targetStore.Find(ctx, filter) + if err != nil { + return nil, stores.ErrTargetNotFound + } + + state := tg.GetState() + + if state.Name == models.ResourceStateNameDeleted && !params.ShowDeleted { + return nil, services.ErrTargetDeleted + } + + var updatedWorkspaces []models.Workspace + for _, w := range tg.Workspaces { + wsState := w.GetState() + if wsState.Name != models.ResourceStateNameDeleted { + updatedWorkspaces = append(updatedWorkspaces, w) + } + } + tg.Workspaces = updatedWorkspaces + + return &services.TargetDTO{ + Target: *tg, + State: state, + }, nil +} diff --git a/pkg/server/targets/list.go b/pkg/server/targets/list.go new file mode 100644 index 0000000000..bc94d88c25 --- /dev/null +++ b/pkg/server/targets/list.go @@ -0,0 +1,45 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package targets + +import ( + "context" + + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/services" + "github.com/daytonaio/daytona/pkg/stores" +) + +func (s *TargetService) List(ctx context.Context, filter *stores.TargetFilter, params services.TargetRetrievalParams) ([]services.TargetDTO, error) { + targets, err := s.targetStore.List(ctx, filter) + if err != nil { + return nil, err + } + + response := []services.TargetDTO{} + + for _, t := range targets { + state := t.GetState() + + if state.Name == models.ResourceStateNameDeleted && !params.ShowDeleted { + continue + } + + var updatedWorkspaces []models.Workspace + for _, w := range t.Workspaces { + wsState := w.GetState() + if wsState.Name != models.ResourceStateNameDeleted { + updatedWorkspaces = append(updatedWorkspaces, w) + } + } + t.Workspaces = updatedWorkspaces + + response = append(response, services.TargetDTO{ + Target: *t, + State: state, + }) + } + + return response, nil +} diff --git a/pkg/server/targets/metadata.go b/pkg/server/targets/metadata.go new file mode 100644 index 0000000000..b97132b4f3 --- /dev/null +++ b/pkg/server/targets/metadata.go @@ -0,0 +1,22 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package targets + +import ( + "context" + + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/stores" +) + +func (s *TargetService) UpdateMetadata(ctx context.Context, targetId string, metadata *models.TargetMetadata) (*models.TargetMetadata, error) { + m, err := s.targetMetadataStore.Find(ctx, targetId) + if err != nil { + return nil, stores.ErrTargetMetadataNotFound + } + + m.Uptime = metadata.Uptime + m.UpdatedAt = metadata.UpdatedAt + return m, s.targetMetadataStore.Save(ctx, m) +} diff --git a/pkg/server/targets/restart.go b/pkg/server/targets/restart.go new file mode 100644 index 0000000000..865aed1cd1 --- /dev/null +++ b/pkg/server/targets/restart.go @@ -0,0 +1,48 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package targets + +import ( + "context" + + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/services" + "github.com/daytonaio/daytona/pkg/stores" + "github.com/daytonaio/daytona/pkg/telemetry" + log "github.com/sirupsen/logrus" +) + +func (s *TargetService) Restart(ctx context.Context, targetId string) error { + target, err := s.targetStore.Find(ctx, &stores.TargetFilter{IdOrName: &targetId}) + if err != nil { + return s.handleRestartError(ctx, nil, stores.ErrTargetNotFound) + } + + if target.TargetConfig.ProviderInfo.AgentlessTarget { + return s.handleRestartError(ctx, target, services.ErrAgentlessTarget) + } + + err = s.createJob(ctx, target.Id, target.TargetConfig.ProviderInfo.RunnerId, models.JobActionRestart) + return s.handleRestartError(ctx, target, err) +} + +func (s *TargetService) handleRestartError(ctx context.Context, target *models.Target, err error) error { + if !telemetry.TelemetryEnabled(ctx) { + return err + } + + clientId := telemetry.ClientId(ctx) + + eventName := telemetry.TargetEventLifecycleRestarted + if err != nil { + eventName = telemetry.TargetEventLifecycleRestartFailed + } + event := telemetry.NewTargetEvent(eventName, target, err, nil) + telemetryError := s.trackTelemetryEvent(event, clientId) + if telemetryError != nil { + log.Trace(telemetryError) + } + + return err +} diff --git a/pkg/server/targets/service.go b/pkg/server/targets/service.go new file mode 100644 index 0000000000..93165081c4 --- /dev/null +++ b/pkg/server/targets/service.go @@ -0,0 +1,105 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package targets + +import ( + "context" + "io" + + "github.com/daytonaio/daytona/pkg/logs" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/services" + "github.com/daytonaio/daytona/pkg/stores" + "github.com/daytonaio/daytona/pkg/telemetry" +) + +type TargetServiceConfig struct { + TargetStore stores.TargetStore + TargetMetadataStore stores.TargetMetadataStore + + FindTargetConfig func(ctx context.Context, name string) (*models.TargetConfig, error) + CreateApiKey func(ctx context.Context, name string) (string, error) + DeleteApiKey func(ctx context.Context, name string) error + CreateJob func(ctx context.Context, targetId string, runnerId string, action models.JobAction) error + TrackTelemetryEvent func(event telemetry.Event, clientId string) error + + ServerApiUrl string + ServerUrl string + ServerVersion string + LoggerFactory logs.ILoggerFactory +} + +func NewTargetService(config TargetServiceConfig) services.ITargetService { + return &TargetService{ + targetStore: config.TargetStore, + targetMetadataStore: config.TargetMetadataStore, + + findTargetConfig: config.FindTargetConfig, + createApiKey: config.CreateApiKey, + deleteApiKey: config.DeleteApiKey, + createJob: config.CreateJob, + + serverApiUrl: config.ServerApiUrl, + serverUrl: config.ServerUrl, + serverVersion: config.ServerVersion, + loggerFactory: config.LoggerFactory, + trackTelemetryEvent: config.TrackTelemetryEvent, + } +} + +type TargetService struct { + targetStore stores.TargetStore + targetMetadataStore stores.TargetMetadataStore + + findTargetConfig func(ctx context.Context, name string) (*models.TargetConfig, error) + createApiKey func(ctx context.Context, name string) (string, error) + deleteApiKey func(ctx context.Context, name string) error + createJob func(ctx context.Context, targetId string, runnerId string, action models.JobAction) error + trackTelemetryEvent func(event telemetry.Event, clientId string) error + + serverApiUrl string + serverUrl string + serverVersion string + loggerFactory logs.ILoggerFactory +} + +func (s *TargetService) GetTargetLogReader(ctx context.Context, targetId string) (io.Reader, error) { + return s.loggerFactory.CreateLogReader(targetId) +} + +func (s *TargetService) GetTargetLogWriter(ctx context.Context, targetId string) (io.WriteCloser, error) { + return s.loggerFactory.CreateLogWriter(targetId) +} + +// TODO: revise - "remove default" is enough for now +func (s *TargetService) Save(ctx context.Context, target *models.Target) error { + return s.targetStore.Save(ctx, target) +} + +func (s *TargetService) UpdateProviderMetadata(ctx context.Context, targetId, metadata string) error { + tg, err := s.targetStore.Find(ctx, &stores.TargetFilter{ + IdOrName: &targetId, + }) + if err != nil { + return err + } + + tg.ProviderMetadata = &metadata + return s.targetStore.Save(ctx, tg) +} + +func (s *TargetService) UpdateLastJob(ctx context.Context, targetId, jobId string) error { + t, err := s.targetStore.Find(ctx, &stores.TargetFilter{ + IdOrName: &targetId, + }) + if err != nil { + return err + } + + t.LastJobId = &jobId + // Make sure the old relation doesn't get saved to the store + t.LastJob = nil + + return s.targetStore.Save(ctx, t) +} diff --git a/pkg/server/targets/service_test.go b/pkg/server/targets/service_test.go new file mode 100644 index 0000000000..ca7fe219ba --- /dev/null +++ b/pkg/server/targets/service_test.go @@ -0,0 +1,239 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package targets_test + +import ( + "context" + "testing" + + "github.com/daytonaio/daytona/internal/testing/job" + t_targetconfigs "github.com/daytonaio/daytona/internal/testing/server/targetconfigs" + t_targets "github.com/daytonaio/daytona/internal/testing/server/targets" + "github.com/daytonaio/daytona/internal/testing/server/targets/mocks" + "github.com/daytonaio/daytona/internal/util" + "github.com/daytonaio/daytona/pkg/logs" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/server/targets" + "github.com/daytonaio/daytona/pkg/services" + "github.com/daytonaio/daytona/pkg/stores" + "github.com/daytonaio/daytona/pkg/telemetry" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" +) + +const serverApiUrl = "http://localhost:3986" +const serverUrl = "http://localhost:3987" + +var tc = models.TargetConfig{ + Id: "test", + Name: "test", + ProviderInfo: models.ProviderInfo{ + Name: "test-provider", + Version: "test", + }, + Options: "test-options", + Deleted: false, +} + +var tg = &models.Target{ + Id: "test", + Name: "test", + ApiKey: "test", + TargetConfigId: tc.Id, + TargetConfig: tc, +} + +var createTargetDTO = services.CreateTargetDTO{ + Name: "test", + Id: "test", + TargetConfigId: "test", +} + +func TestTargetService(t *testing.T) { + tg.EnvVars = targets.GetTargetEnvVars(tg, targets.TargetEnvVarParams{ + ApiUrl: serverApiUrl, + ServerUrl: serverUrl, + ClientId: "test-client-id", + }) + + ctx := context.Background() + ctx = context.WithValue(ctx, telemetry.CLIENT_ID_CONTEXT_KEY, "test-client-id") + + jobStore := job.NewInMemoryJobStore() + + targetStore := t_targets.NewInMemoryTargetStore(jobStore) + targetMetadataStore := t_targets.NewInMemoryTargetMetadataStore() + targetConfigStore := t_targetconfigs.NewInMemoryTargetConfigStore() + + err := targetConfigStore.Save(ctx, &tc) + require.Nil(t, err) + + apiKeyService := mocks.NewMockApiKeyService() + + tgLogsDir := t.TempDir() + + service := targets.NewTargetService(targets.TargetServiceConfig{ + TargetStore: targetStore, + TargetMetadataStore: targetMetadataStore, + FindTargetConfig: func(ctx context.Context, name string) (*models.TargetConfig, error) { + return targetConfigStore.Find(ctx, name, false) + }, + CreateApiKey: func(ctx context.Context, name string) (string, error) { + return apiKeyService.Create(models.ApiKeyTypeTarget, name) + }, + DeleteApiKey: func(ctx context.Context, name string) error { + return apiKeyService.Delete(name) + }, + ServerApiUrl: serverApiUrl, + ServerUrl: serverUrl, + LoggerFactory: logs.NewLoggerFactory(logs.LoggerFactoryConfig{LogsDir: tgLogsDir}), + TrackTelemetryEvent: func(event telemetry.Event, clientId string) error { + return nil + }, + CreateJob: func(ctx context.Context, targetId, runnerId string, action models.JobAction) error { + return jobStore.Save(ctx, &models.Job{ + Id: targetId, + ResourceId: targetId, + RunnerId: util.Pointer(runnerId), + ResourceType: models.ResourceTypeTarget, + Action: action, + State: models.JobStateSuccess, + }) + }, + }) + + t.Run("CreateTarget", func(t *testing.T) { + apiKeyService.On("Create", models.ApiKeyTypeTarget, createTargetDTO.Id).Return(createTargetDTO.Id, nil) + + target, err := service.Create(ctx, createTargetDTO) + + require.Nil(t, err) + require.NotNil(t, target) + + targetEquals(t, tg, target) + + tg.EnvVars = nil + tg.ApiKey = "" + }) + + t.Run("CreateTarget fails when target already exists", func(t *testing.T) { + _, err := service.Create(ctx, createTargetDTO) + require.NotNil(t, err) + require.Equal(t, services.ErrTargetAlreadyExists, err) + }) + + t.Run("FindTarget", func(t *testing.T) { + target, err := service.Find(ctx, &stores.TargetFilter{IdOrName: &createTargetDTO.Id}, services.TargetRetrievalParams{}) + + require.Nil(t, err) + require.NotNil(t, target) + + targetDtoEquals(t, createTargetDTO, *target) + }) + + t.Run("FindTarget fails when target not found", func(t *testing.T) { + _, err := service.Find(ctx, &stores.TargetFilter{IdOrName: util.Pointer("invalid-id")}, services.TargetRetrievalParams{}) + require.NotNil(t, err) + require.Equal(t, stores.ErrTargetNotFound, err) + }) + + t.Run("ListTargets", func(t *testing.T) { + targets, err := service.List(ctx, nil, services.TargetRetrievalParams{}) + + require.Nil(t, err) + require.Len(t, targets, 1) + + target := targets[0] + + targetDtoEquals(t, createTargetDTO, target) + }) + + t.Run("StartTarget", func(t *testing.T) { + tg.EnvVars = targets.GetTargetEnvVars(tg, targets.TargetEnvVarParams{ + ApiUrl: serverApiUrl, + ServerUrl: serverUrl, + ClientId: "test-client-id", + }) + + err := service.Start(ctx, createTargetDTO.Id) + + require.Nil(t, err) + + tg.EnvVars = nil + }) + + t.Run("StopTarget", func(t *testing.T) { + err := service.Stop(ctx, createTargetDTO.Id) + + require.Nil(t, err) + }) + + t.Run("UpdateTargetMetadata", func(t *testing.T) { + err := targetStore.Save(ctx, tg) + require.Nil(t, err) + + _, err = service.UpdateMetadata(context.TODO(), tg.Id, &models.TargetMetadata{ + Uptime: 10, + }) + require.Nil(t, err) + }) + + t.Run("DeleteTarget", func(t *testing.T) { + apiKeyService.On("Delete", mock.Anything).Return(nil) + + err := service.Delete(ctx, createTargetDTO.Id) + + require.Nil(t, err) + + _, err = service.Find(ctx, &stores.TargetFilter{IdOrName: &createTargetDTO.Id}, services.TargetRetrievalParams{}) + require.Equal(t, services.ErrTargetDeleted, err) + }) + + t.Run("ForceDeleteTarget", func(t *testing.T) { + err := targetStore.Save(ctx, tg) + require.Nil(t, err) + + apiKeyService.On("Delete", mock.Anything).Return(nil) + + err = service.ForceDelete(ctx, createTargetDTO.Id) + + require.Nil(t, err) + + _, err = service.Find(ctx, &stores.TargetFilter{IdOrName: &createTargetDTO.Id}, services.TargetRetrievalParams{}) + require.Equal(t, services.ErrTargetDeleted, err) + }) + + t.Run("CreateTarget fails name validation", func(t *testing.T) { + invalidTargetRequest := createTargetDTO + invalidTargetRequest.Id = "some-id" + invalidTargetRequest.Name = "invalid name" + + _, err := service.Create(ctx, invalidTargetRequest) + require.NotNil(t, err) + require.Equal(t, services.ErrInvalidTargetName, err) + }) + + t.Cleanup(func() { + apiKeyService.AssertExpectations(t) + }) +} + +func targetEquals(t *testing.T, t1, t2 *models.Target) { + t.Helper() + + require.Equal(t, t1.Id, t2.Id) + require.Equal(t, t1.Name, t2.Name) + require.Equal(t, t1.TargetConfig.ProviderInfo, t2.TargetConfig.ProviderInfo) + require.Equal(t, t1.TargetConfig.Options, t2.TargetConfig.Options) + require.Equal(t, t1.IsDefault, t2.IsDefault) +} + +func targetDtoEquals(t *testing.T, req services.CreateTargetDTO, target services.TargetDTO) { + t.Helper() + + require.Equal(t, req.Id, target.Id) + require.Equal(t, req.Name, target.Name) + require.Equal(t, tc.ProviderInfo, target.TargetConfig.ProviderInfo) + require.Equal(t, tc.Options, target.TargetConfig.Options) +} diff --git a/pkg/server/targets/set-default.go b/pkg/server/targets/set-default.go new file mode 100644 index 0000000000..bcc67d8cb5 --- /dev/null +++ b/pkg/server/targets/set-default.go @@ -0,0 +1,52 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package targets + +import ( + "context" + + "github.com/daytonaio/daytona/internal/util" + "github.com/daytonaio/daytona/pkg/services" + "github.com/daytonaio/daytona/pkg/stores" +) + +func (s *TargetService) SetDefault(ctx context.Context, id string) error { + var err error + ctx, err = s.targetStore.BeginTransaction(ctx) + if err != nil { + return err + } + + defer stores.RecoverAndRollback(ctx, s.targetStore) + + currentTarget, err := s.Find(ctx, &stores.TargetFilter{ + IdOrName: &id, + }, services.TargetRetrievalParams{}) + if err != nil || currentTarget == nil { + return s.targetStore.RollbackTransaction(ctx, err) + } + + defaultTarget, err := s.Find(ctx, &stores.TargetFilter{ + Default: util.Pointer(true), + }, services.TargetRetrievalParams{ShowDeleted: true}) + if err != nil && !stores.IsTargetNotFound(err) { + return s.targetStore.RollbackTransaction(ctx, err) + } + + if defaultTarget != nil { + defaultTarget.IsDefault = false + err := s.targetStore.Save(ctx, &defaultTarget.Target) + if err != nil { + return s.targetStore.RollbackTransaction(ctx, err) + } + } + + currentTarget.IsDefault = true + err = s.targetStore.Save(ctx, ¤tTarget.Target) + if err != nil { + return s.targetStore.RollbackTransaction(ctx, err) + } + + return s.targetStore.CommitTransaction(ctx) +} diff --git a/pkg/server/targets/start.go b/pkg/server/targets/start.go new file mode 100644 index 0000000000..c946f55f40 --- /dev/null +++ b/pkg/server/targets/start.go @@ -0,0 +1,48 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package targets + +import ( + "context" + + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/services" + "github.com/daytonaio/daytona/pkg/stores" + "github.com/daytonaio/daytona/pkg/telemetry" + log "github.com/sirupsen/logrus" +) + +func (s *TargetService) Start(ctx context.Context, targetId string) error { + target, err := s.targetStore.Find(ctx, &stores.TargetFilter{IdOrName: &targetId}) + if err != nil { + return s.handleStartError(ctx, nil, stores.ErrTargetNotFound) + } + + if target.TargetConfig.ProviderInfo.AgentlessTarget { + return s.handleStartError(ctx, target, services.ErrAgentlessTarget) + } + + err = s.createJob(ctx, target.Id, target.TargetConfig.ProviderInfo.RunnerId, models.JobActionStart) + return s.handleStartError(ctx, target, err) +} + +func (s *TargetService) handleStartError(ctx context.Context, target *models.Target, err error) error { + if !telemetry.TelemetryEnabled(ctx) { + return err + } + + clientId := telemetry.ClientId(ctx) + + eventName := telemetry.TargetEventLifecycleStarted + if err != nil { + eventName = telemetry.TargetEventLifecycleStartFailed + } + event := telemetry.NewTargetEvent(eventName, target, err, nil) + telemetryError := s.trackTelemetryEvent(event, clientId) + if telemetryError != nil { + log.Trace(telemetryError) + } + + return err +} diff --git a/pkg/server/targets/stop.go b/pkg/server/targets/stop.go new file mode 100644 index 0000000000..1a5c55b89b --- /dev/null +++ b/pkg/server/targets/stop.go @@ -0,0 +1,49 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package targets + +import ( + "context" + + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/services" + "github.com/daytonaio/daytona/pkg/stores" + "github.com/daytonaio/daytona/pkg/telemetry" + log "github.com/sirupsen/logrus" +) + +func (s *TargetService) Stop(ctx context.Context, targetId string) error { + target, err := s.targetStore.Find(ctx, &stores.TargetFilter{IdOrName: &targetId}) + if err != nil { + return s.handleStopError(ctx, nil, stores.ErrTargetNotFound) + } + + if target.TargetConfig.ProviderInfo.AgentlessTarget { + return s.handleStartError(ctx, target, services.ErrAgentlessTarget) + } + + err = s.createJob(ctx, target.Id, target.TargetConfig.ProviderInfo.RunnerId, models.JobActionStop) + return s.handleStopError(ctx, target, err) +} + +func (s *TargetService) handleStopError(ctx context.Context, target *models.Target, err error) error { + if !telemetry.TelemetryEnabled(ctx) { + return err + } + + clientId := telemetry.ClientId(ctx) + + eventName := telemetry.TargetEventLifecycleStopped + if err != nil { + eventName = telemetry.TargetEventLifecycleStopFailed + } + event := telemetry.NewTargetEvent(eventName, target, err, nil) + + telemetryError := s.trackTelemetryEvent(event, clientId) + if telemetryError != nil { + log.Trace(telemetryError) + } + + return err +} diff --git a/pkg/server/types.go b/pkg/server/types.go index f4ade4a774..9159f04fdb 100644 --- a/pkg/server/types.go +++ b/pkg/server/types.go @@ -7,12 +7,14 @@ import ( "context" "net" "net/http" + + "github.com/daytonaio/daytona/pkg/logs" ) type TailscaleServer interface { - Connect() error - CreateAuthKey() (string, error) - CreateUser() error + Connect(username string) error + CreateAuthKey(username string) (string, error) + CreateUser(username string) error HTTPClient() *http.Client Dial(ctx context.Context, network, address string) (net.Conn, error) Start(errChan chan error) error @@ -37,30 +39,21 @@ type NetworkKey struct { } // @name NetworkKey type Config struct { - ProvidersDir string `json:"providersDir" validate:"required"` - RegistryUrl string `json:"registryUrl" validate:"required"` - Id string `json:"id" validate:"required"` - ServerDownloadUrl string `json:"serverDownloadUrl" validate:"required"` - Frps *FRPSConfig `json:"frps,omitempty" validate:"optional"` - ApiPort uint32 `json:"apiPort" validate:"required"` - HeadscalePort uint32 `json:"headscalePort" validate:"required"` - BinariesPath string `json:"binariesPath" validate:"required"` - LogFile *LogFileConfig `json:"logFile" validate:"required"` - DefaultProjectImage string `json:"defaultProjectImage" validate:"required"` - DefaultProjectUser string `json:"defaultProjectUser" validate:"required"` - BuilderImage string `json:"builderImage" validate:"required"` - LocalBuilderRegistryPort uint32 `json:"localBuilderRegistryPort" validate:"required"` - LocalBuilderRegistryImage string `json:"localBuilderRegistryImage" validate:"required"` - BuilderRegistryServer string `json:"builderRegistryServer" validate:"required"` - BuildImageNamespace string `json:"buildImageNamespace" validate:"optional"` - SamplesIndexUrl string `json:"samplesIndexUrl" validate:"optional"` + RegistryUrl string `json:"registryUrl" validate:"required"` + Id string `json:"id" validate:"required"` + ServerDownloadUrl string `json:"serverDownloadUrl" validate:"required"` + Frps *FRPSConfig `json:"frps,omitempty" validate:"optional"` + ApiPort uint32 `json:"apiPort" validate:"required"` + HeadscalePort uint32 `json:"headscalePort" validate:"required"` + BinariesPath string `json:"binariesPath" validate:"required"` + LogFile *logs.LogFileConfig `json:"logFile" validate:"required"` + BuilderImage string `json:"builderImage" validate:"required"` + DefaultWorkspaceImage string `json:"defaultWorkspaceImage" validate:"required"` + DefaultWorkspaceUser string `json:"defaultWorkspaceUser" validate:"required"` + LocalBuilderRegistryPort uint32 `json:"localBuilderRegistryPort" validate:"required"` + LocalBuilderRegistryImage string `json:"localBuilderRegistryImage" validate:"required"` + BuilderRegistryServer string `json:"builderRegistryServer" validate:"required"` + BuildImageNamespace string `json:"buildImageNamespace" validate:"optional"` + LocalRunnerDisabled *bool `json:"localRunnerDisabled" validate:"optional"` + SamplesIndexUrl string `json:"samplesIndexUrl" validate:"optional"` } // @name ServerConfig - -type LogFileConfig struct { - Path string `json:"path" validate:"required"` - MaxSize int `json:"maxSize" validate:"required"` - MaxBackups int `json:"maxBackups" validate:"required"` - MaxAge int `json:"maxAge" validate:"required"` - LocalTime bool `json:"localTime" validate:"optional"` - Compress bool `json:"compress" validate:"optional"` -} // @name LogFileConfig diff --git a/pkg/server/workspaces/create.go b/pkg/server/workspaces/create.go index acb5afa54d..a66dea60ce 100644 --- a/pkg/server/workspaces/create.go +++ b/pkg/server/workspaces/create.go @@ -6,282 +6,176 @@ package workspaces import ( "context" "errors" - "fmt" - "io" "regexp" "github.com/daytonaio/daytona/internal/util" - "github.com/daytonaio/daytona/internal/util/apiclient/conversion" - "github.com/daytonaio/daytona/pkg/apikey" - "github.com/daytonaio/daytona/pkg/build" - "github.com/daytonaio/daytona/pkg/containerregistry" - "github.com/daytonaio/daytona/pkg/gitprovider" - "github.com/daytonaio/daytona/pkg/logs" - "github.com/daytonaio/daytona/pkg/provider" - "github.com/daytonaio/daytona/pkg/provisioner" - "github.com/daytonaio/daytona/pkg/server/workspaces/dto" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/services" + "github.com/daytonaio/daytona/pkg/stores" "github.com/daytonaio/daytona/pkg/telemetry" - "github.com/daytonaio/daytona/pkg/workspace" - "github.com/daytonaio/daytona/pkg/workspace/project" - "github.com/daytonaio/daytona/pkg/workspace/project/buildconfig" log "github.com/sirupsen/logrus" ) -func isValidWorkspaceName(name string) bool { - // The repository name can only contain ASCII letters, digits, and the characters ., -, and _. - var validName = regexp.MustCompile(`^[a-zA-Z0-9._-]+$`) - - // Check if the name matches the basic regex - if !validName.MatchString(name) { - return false - } - - // Names starting with a period must have atleast one char appended to it. - if name == "." || name == "" { - return false +func (s *WorkspaceService) Create(ctx context.Context, req services.CreateWorkspaceDTO) (*services.WorkspaceDTO, error) { + var err error + ctx, err = s.workspaceStore.BeginTransaction(ctx) + if err != nil { + return s.handleCreateError(ctx, nil, err) } - return true -} + defer stores.RecoverAndRollback(ctx, s.workspaceStore) -func (s *WorkspaceService) CreateWorkspace(ctx context.Context, req dto.CreateWorkspaceDTO) (*workspace.Workspace, error) { - _, err := s.workspaceStore.Find(req.Name) + _, err = s.workspaceStore.Find(ctx, req.Name) if err == nil { - return nil, ErrWorkspaceAlreadyExists + return s.handleCreateError(ctx, nil, services.ErrWorkspaceAlreadyExists) } - // Repo name is taken as the name for workspace by default - if !isValidWorkspaceName(req.Name) { - return nil, ErrInvalidWorkspaceName - } - - w := &workspace.Workspace{ - Id: req.Id, - Name: req.Name, - Target: req.Target, - } - - apiKey, err := s.apiKeyService.Generate(apikey.ApiKeyTypeWorkspace, w.Id) + target, err := s.findTarget(ctx, req.TargetId) if err != nil { - return nil, err + return s.handleCreateError(ctx, nil, err) } - w.ApiKey = apiKey - - w.Projects = []*project.Project{} - - for _, projectDto := range req.Projects { - p := conversion.CreateDtoToProject(projectDto) - isValidProjectName := regexp.MustCompile(`^[a-zA-Z0-9-_.]+$`).MatchString - if !isValidProjectName(p.Name) { - return nil, ErrInvalidProjectName - } - - p.Repository.Url = util.CleanUpRepositoryUrl(p.Repository.Url) - if p.GitProviderConfigId == nil || *p.GitProviderConfigId == "" { - configs, err := s.gitProviderService.ListConfigsForUrl(p.Repository.Url) - if err != nil { - return nil, err - } + w := req.ToWorkspace() + w.Target = *target - if len(configs) > 1 { - return nil, errors.New("multiple git provider configs found for the repository url") - } + if !isValidWorkspaceName(w.Name) { + return s.handleCreateError(ctx, w, services.ErrInvalidWorkspaceName) + } - if len(configs) == 1 { - p.GitProviderConfigId = &configs[0].Id - } - } + w.Repository.Url = util.CleanUpRepositoryUrl(w.Repository.Url) - if p.Repository.Sha == "" { - sha, err := s.gitProviderService.GetLastCommitSha(p.Repository) - if err != nil { - return nil, err - } - p.Repository.Sha = sha + if w.GitProviderConfigId == nil || *w.GitProviderConfigId == "" { + configs, err := s.listGitProviderConfigs(ctx, w.Repository.Url) + if err != nil { + return s.handleCreateError(ctx, w, err) } - if p.BuildConfig != nil { - cachedBuild, err := s.getCachedBuildForProject(p) - if err == nil { - p.BuildConfig.CachedBuild = cachedBuild - } + if len(configs) > 1 { + return s.handleCreateError(ctx, w, errors.New("multiple git provider configs found for the repository url")) } - if p.Image == "" { - p.Image = s.defaultProjectImage + if len(configs) == 1 { + w.GitProviderConfigId = &configs[0].Id } + } - if p.User == "" { - p.User = s.defaultProjectUser - } + if w.GitProviderConfigId != nil && *w.GitProviderConfigId == "" { + w.GitProviderConfigId = nil + } - apiKey, err := s.apiKeyService.Generate(apikey.ApiKeyTypeProject, fmt.Sprintf("%s/%s", w.Id, p.Name)) + if w.Repository.Sha == "" { + sha, err := s.getLastCommitSha(ctx, w.Repository) if err != nil { - return nil, err + return s.handleCreateError(ctx, w, err) } - - p.WorkspaceId = w.Id - p.ApiKey = apiKey - p.Target = w.Target - w.Projects = append(w.Projects, p) + w.Repository.Sha = sha } - err = s.workspaceStore.Save(w) - if err != nil { - return nil, err + if w.BuildConfig != nil { + cachedBuild, err := s.findCachedBuild(ctx, w) + if err == nil { + w.BuildConfig.CachedBuild = cachedBuild + } } - target, err := s.targetStore.Find(&provider.TargetFilter{Name: &w.Target}) - if err != nil { - return w, err + if w.Image == "" { + w.Image = s.defaultWorkspaceImage } - w, err = s.createWorkspace(ctx, w, target) - - if !telemetry.TelemetryEnabled(ctx) { - return w, err + if w.User == "" { + w.User = s.defaultWorkspaceUser } - clientId := telemetry.ClientId(ctx) - - telemetryProps := telemetry.NewWorkspaceEventProps(ctx, w, target) - event := telemetry.ServerEventWorkspaceCreated + apiKey, err := s.createApiKey(ctx, w.Id) if err != nil { - telemetryProps["error"] = err.Error() - event = telemetry.ServerEventWorkspaceCreateError - } - telemetryError := s.telemetryService.TrackServerEvent(event, clientId, telemetryProps) - if telemetryError != nil { - log.Trace(err) - } - - return w, err -} - -func (s *WorkspaceService) createProject(p *project.Project, target *provider.ProviderTarget, logWriter io.Writer) error { - logWriter.Write([]byte(fmt.Sprintf("Creating project %s\n", p.Name))) - - cr, err := s.containerRegistryService.FindByImageName(p.Image) - if err != nil && !containerregistry.IsContainerRegistryNotFound(err) { - return err + return s.handleCreateError(ctx, w, err) } + w.ApiKey = apiKey - builderCr, err := s.containerRegistryService.FindByImageName(s.builderImage) - if err != nil && !containerregistry.IsContainerRegistryNotFound(err) { - return err + err = s.workspaceMetadataStore.Save(ctx, &models.WorkspaceMetadata{ + WorkspaceId: w.Id, + Uptime: 0, + GitStatus: &models.GitStatus{}, + }) + if err != nil { + return s.handleCreateError(ctx, w, err) } - var gc *gitprovider.GitProviderConfig + daytonaWorkspaceEnvVars := GetWorkspaceEnvVars(w, WorkspaceEnvVarParams{ + ApiUrl: s.serverApiUrl, + ServerUrl: s.serverUrl, + ServerVersion: s.serverVersion, + ClientId: telemetry.ClientId(ctx), + TelemetryEnabled: telemetry.TelemetryEnabled(ctx), + }) + w.EnvVars = util.MergeEnvVars(daytonaWorkspaceEnvVars, w.EnvVars) - if p.GitProviderConfigId != nil { - gc, err = s.gitProviderService.GetConfig(*p.GitProviderConfigId) - if err != nil && !gitprovider.IsGitProviderNotFound(err) { - return err - } + err = s.workspaceStore.Save(ctx, w) + if err != nil { + return s.handleCreateError(ctx, w, err) } - err = s.provisioner.CreateProject(provisioner.ProjectParams{ - Project: p, - Target: target, - ContainerRegistry: cr, - GitProviderConfig: gc, - BuilderImage: s.builderImage, - BuilderImageContainerRegistry: builderCr, - }) + err = s.createJob(ctx, w.Id, w.Target.TargetConfig.ProviderInfo.RunnerId, models.JobActionCreate) if err != nil { - return err + return s.handleCreateError(ctx, w, err) } - logWriter.Write([]byte(fmt.Sprintf("Project %s created\n", p.Name))) - - return nil + err = s.workspaceStore.CommitTransaction(ctx) + return s.handleCreateError(ctx, w, err) } -func (s *WorkspaceService) createWorkspace(ctx context.Context, ws *workspace.Workspace, target *provider.ProviderTarget) (*workspace.Workspace, error) { - wsLogger := s.loggerFactory.CreateWorkspaceLogger(ws.Id, logs.LogSourceServer) - defer wsLogger.Close() - - wsLogger.Write([]byte(fmt.Sprintf("Creating workspace %s (%s)\n", ws.Name, ws.Id))) - - ws.EnvVars = workspace.GetWorkspaceEnvVars(ws, workspace.WorkspaceEnvVarParams{ - ApiUrl: s.serverApiUrl, - ServerUrl: s.serverUrl, - ServerVersion: s.serverVersion, - ClientId: telemetry.ClientId(ctx), - }, telemetry.TelemetryEnabled(ctx)) - - err := s.provisioner.CreateWorkspace(ws, target) +func (s *WorkspaceService) handleCreateError(ctx context.Context, w *models.Workspace, err error) (*services.WorkspaceDTO, error) { if err != nil { - return nil, err + err = s.workspaceStore.RollbackTransaction(ctx, err) } - for i, p := range ws.Projects { - projectLogger := s.loggerFactory.CreateProjectLogger(ws.Id, p.Name, logs.LogSourceServer) - defer projectLogger.Close() - - projectWithEnv := *p - projectWithEnv.EnvVars = project.GetProjectEnvVars(p, project.ProjectEnvVarParams{ - ApiUrl: s.serverApiUrl, - ServerUrl: s.serverUrl, - ServerVersion: s.serverVersion, - ClientId: telemetry.ClientId(ctx), - }, telemetry.TelemetryEnabled(ctx)) - - for k, v := range p.EnvVars { - projectWithEnv.EnvVars[k] = v - } - - var err error - - p = &projectWithEnv - - ws.Projects[i] = p - err = s.workspaceStore.Save(ws) - if err != nil { - return nil, err - } - - err = s.createProject(p, target, projectLogger) - if err != nil { + if !telemetry.TelemetryEnabled(ctx) { + if w == nil { return nil, err } + return &services.WorkspaceDTO{ + Workspace: *w, + State: w.GetState(), + }, err } - wsLogger.Write([]byte("Workspace creation complete. Pending start...\n")) + clientId := telemetry.ClientId(ctx) - err = s.startWorkspace(ctx, ws, target, wsLogger) + eventName := telemetry.WorkspaceEventLifecycleCreated if err != nil { + eventName = telemetry.WorkspaceEventLifecycleCreationFailed + } + event := telemetry.NewWorkspaceEvent(eventName, w, err, nil) + + telemetryError := s.trackTelemetryEvent(event, clientId) + if telemetryError != nil { + log.Trace(telemetryError) + } + + if w == nil { return nil, err } - return ws, nil + return &services.WorkspaceDTO{ + Workspace: *w, + State: w.GetState(), + }, err } -func (s *WorkspaceService) getCachedBuildForProject(p *project.Project) (*buildconfig.CachedBuild, error) { - validStates := &[]build.BuildState{ - build.BuildState(build.BuildStatePublished), - } +func isValidWorkspaceName(name string) bool { + // The repository name can only contain ASCII letters, digits, and the characters ., -, and _. + var validName = regexp.MustCompile(`^[a-zA-Z0-9._-]+$`) - build, err := s.buildService.Find(&build.Filter{ - States: validStates, - RepositoryUrl: &p.Repository.Url, - Branch: &p.Repository.Branch, - EnvVars: &p.EnvVars, - BuildConfig: p.BuildConfig, - GetNewest: util.Pointer(true), - }) - if err != nil { - return nil, err + // Check if the name matches the basic regex + if !validName.MatchString(name) { + return false } - if build.Image == nil || build.User == nil { - return nil, errors.New("cached build is missing image or user") + // Names starting with a period must have atleast one char appended to it. + if name == "." || name == "" { + return false } - return &buildconfig.CachedBuild{ - User: *build.User, - Image: *build.Image, - }, nil + return true } diff --git a/pkg/server/workspaces/delete.go b/pkg/server/workspaces/delete.go new file mode 100644 index 0000000000..127613be95 --- /dev/null +++ b/pkg/server/workspaces/delete.go @@ -0,0 +1,151 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package workspaces + +import ( + "context" + + "github.com/daytonaio/daytona/internal/util" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/stores" + "github.com/daytonaio/daytona/pkg/telemetry" + log "github.com/sirupsen/logrus" +) + +func (s *WorkspaceService) Delete(ctx context.Context, workspaceId string) error { + var err error + ctx, err = s.workspaceStore.BeginTransaction(ctx) + if err != nil { + return s.handleDeleteError(ctx, nil, err) + } + + defer stores.RecoverAndRollback(ctx, s.workspaceStore) + + w, err := s.workspaceStore.Find(ctx, workspaceId) + if err != nil { + return s.handleDeleteError(ctx, w, stores.ErrWorkspaceNotFound) + } + + w.Name = util.AddDeletedToName(w.Name) + + err = s.workspaceStore.Save(ctx, w) + if err != nil { + return s.handleDeleteError(ctx, w, err) + } + + err = s.deleteApiKey(ctx, workspaceId) + if err != nil { + return s.handleDeleteError(ctx, w, err) + } + + metadata, err := s.workspaceMetadataStore.Find(ctx, workspaceId) + if err == nil { + err = s.workspaceMetadataStore.Delete(ctx, metadata) + if err != nil { + return s.handleDeleteError(ctx, w, err) + } + } + + err = s.createJob(ctx, w.Id, w.Target.TargetConfig.ProviderInfo.RunnerId, models.JobActionDelete) + if err != nil { + return s.handleDeleteError(ctx, w, err) + } + + err = s.workspaceStore.CommitTransaction(ctx) + return s.handleDeleteError(ctx, w, err) +} + +// ForceDelete ignores provider errors and makes sure the workspace is removed from storage. +func (s *WorkspaceService) ForceDelete(ctx context.Context, workspaceId string) error { + var err error + ctx, err = s.workspaceStore.BeginTransaction(ctx) + if err != nil { + return s.handleForceDeleteError(ctx, nil, err) + } + + defer stores.RecoverAndRollback(ctx, s.workspaceStore) + + w, err := s.workspaceStore.Find(ctx, workspaceId) + if err != nil { + return s.handleForceDeleteError(ctx, w, stores.ErrWorkspaceNotFound) + } + + w.Name = util.AddDeletedToName(w.Name) + + err = s.workspaceStore.Save(ctx, w) + if err != nil { + return s.handleForceDeleteError(ctx, w, err) + } + + err = s.deleteApiKey(ctx, workspaceId) + if err != nil { + log.Error(err) + } + + metadata, err := s.workspaceMetadataStore.Find(ctx, workspaceId) + if err == nil { + err = s.workspaceMetadataStore.Delete(ctx, metadata) + if err != nil { + log.Error(err) + } + } + + err = s.createJob(ctx, w.Id, w.Target.TargetConfig.ProviderInfo.RunnerId, models.JobActionForceDelete) + if err != nil { + return s.handleForceDeleteError(ctx, w, err) + } + + err = s.workspaceStore.CommitTransaction(ctx) + return s.handleForceDeleteError(ctx, w, err) +} + +func (s *WorkspaceService) handleDeleteError(ctx context.Context, w *models.Workspace, err error) error { + if err != nil { + err = s.workspaceStore.RollbackTransaction(ctx, err) + } + + if !telemetry.TelemetryEnabled(ctx) { + return err + } + + clientId := telemetry.ClientId(ctx) + + eventName := telemetry.WorkspaceEventLifecycleDeleted + if err != nil { + eventName = telemetry.WorkspaceEventLifecycleDeletionFailed + } + event := telemetry.NewWorkspaceEvent(eventName, w, err, nil) + + telemetryError := s.trackTelemetryEvent(event, clientId) + if telemetryError != nil { + log.Trace(telemetryError) + } + + return err +} + +func (s *WorkspaceService) handleForceDeleteError(ctx context.Context, w *models.Workspace, err error) error { + if err != nil { + err = s.workspaceStore.RollbackTransaction(ctx, err) + } + + if !telemetry.TelemetryEnabled(ctx) { + return err + } + + clientId := telemetry.ClientId(ctx) + + eventName := telemetry.WorkspaceEventLifecycleForceDeleted + if err != nil { + eventName = telemetry.WorkspaceEventLifecycleForceDeletionFailed + } + event := telemetry.NewWorkspaceEvent(eventName, w, err, nil) + + telemetryError := s.trackTelemetryEvent(event, clientId) + if telemetryError != nil { + log.Trace(telemetryError) + } + + return err +} diff --git a/pkg/server/workspaces/dto/workspace.go b/pkg/server/workspaces/dto/workspace.go deleted file mode 100644 index a5fea289ad..0000000000 --- a/pkg/server/workspaces/dto/workspace.go +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package dto - -import ( - "github.com/daytonaio/daytona/pkg/gitprovider" - "github.com/daytonaio/daytona/pkg/workspace" - "github.com/daytonaio/daytona/pkg/workspace/project" - "github.com/daytonaio/daytona/pkg/workspace/project/buildconfig" -) - -type WorkspaceDTO struct { - workspace.Workspace - Info *workspace.WorkspaceInfo `json:"info" validate:"optional"` -} // @name WorkspaceDTO - -type ProjectDTO struct { - project.Project - Info *project.ProjectInfo `json:"info" validate:"optional"` -} // @name ProjectDTO - -type CreateWorkspaceDTO struct { - Id string `json:"id" validate:"required"` - Name string `json:"name" validate:"required"` - Target string `json:"target" validate:"required"` - Projects []CreateProjectDTO `json:"projects" validate:"required,gt=0,dive"` -} // @name CreateWorkspaceDTO - -type CreateProjectDTO struct { - Name string `json:"name" validate:"required"` - Image *string `json:"image,omitempty" validate:"optional"` - User *string `json:"user,omitempty" validate:"optional"` - BuildConfig *buildconfig.BuildConfig `json:"buildConfig,omitempty" validate:"optional"` - Source CreateProjectSourceDTO `json:"source" validate:"required"` - EnvVars map[string]string `json:"envVars" validate:"required"` - GitProviderConfigId *string `json:"gitProviderConfigId" validate:"optional"` -} // @name CreateProjectDTO - -type CreateProjectSourceDTO struct { - Repository *gitprovider.GitRepository `json:"repository" validate:"required"` -} // @name CreateProjectSourceDTO diff --git a/pkg/server/workspaces/env_vars.go b/pkg/server/workspaces/env_vars.go new file mode 100644 index 0000000000..cb5937a232 --- /dev/null +++ b/pkg/server/workspaces/env_vars.go @@ -0,0 +1,35 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package workspaces + +import "github.com/daytonaio/daytona/pkg/models" + +type WorkspaceEnvVarParams struct { + ApiUrl string + ServerUrl string + ServerVersion string + ClientId string + TelemetryEnabled bool +} + +func GetWorkspaceEnvVars(workspace *models.Workspace, params WorkspaceEnvVarParams) map[string]string { + envVars := map[string]string{ + "DAYTONA_TARGET_ID": workspace.TargetId, + "DAYTONA_WORKSPACE_ID": workspace.Id, + "DAYTONA_WORKSPACE_REPOSITORY_URL": workspace.Repository.Url, + "DAYTONA_SERVER_API_KEY": workspace.ApiKey, + "DAYTONA_SERVER_VERSION": params.ServerVersion, + "DAYTONA_SERVER_URL": params.ServerUrl, + "DAYTONA_SERVER_API_URL": params.ApiUrl, + "DAYTONA_CLIENT_ID": params.ClientId, + // (HOME) will be replaced at runtime + "DAYTONA_AGENT_LOG_FILE_PATH": "(HOME)/.daytona-agent.log", + } + + if params.TelemetryEnabled { + envVars["DAYTONA_TELEMETRY_ENABLED"] = "true" + } + + return envVars +} diff --git a/pkg/server/workspaces/error.go b/pkg/server/workspaces/error.go deleted file mode 100644 index 55fee21339..0000000000 --- a/pkg/server/workspaces/error.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package workspaces - -import ( - "errors" -) - -var ( - ErrWorkspaceAlreadyExists = errors.New("workspace already exists") - ErrInvalidWorkspaceName = errors.New("name is not a valid alphanumeric string") - ErrWorkspaceNotFound = errors.New("workspace not found") - ErrProjectNotFound = errors.New("project not found") - ErrInvalidProjectName = errors.New("project name is not valid. Only [a-zA-Z0-9-_.] are allowed") - ErrInvalidProjectConfig = errors.New("project config is invalid") -) - -func IsWorkspaceAlreadyExists(err error) bool { - return err.Error() == ErrWorkspaceAlreadyExists.Error() -} - -func IsWorkspaceNotFound(err error) bool { - return err.Error() == ErrWorkspaceNotFound.Error() -} - -func IsProjectNotFound(err error) bool { - return err.Error() == ErrProjectNotFound.Error() -} - -func IsInvalidWorkspaceName(err error) bool { - return err.Error() == ErrInvalidWorkspaceName.Error() -} diff --git a/pkg/server/workspaces/find.go b/pkg/server/workspaces/find.go new file mode 100644 index 0000000000..da6af57fa7 --- /dev/null +++ b/pkg/server/workspaces/find.go @@ -0,0 +1,30 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package workspaces + +import ( + "context" + + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/services" + "github.com/daytonaio/daytona/pkg/stores" +) + +func (s *WorkspaceService) Find(ctx context.Context, workspaceId string, params services.WorkspaceRetrievalParams) (*services.WorkspaceDTO, error) { + w, err := s.workspaceStore.Find(ctx, workspaceId) + if err != nil { + return nil, stores.ErrWorkspaceNotFound + } + + state := w.GetState() + + if state.Name == models.ResourceStateNameDeleted && !params.ShowDeleted { + return nil, services.ErrWorkspaceDeleted + } + + return &services.WorkspaceDTO{ + Workspace: *w, + State: state, + }, nil +} diff --git a/pkg/server/workspaces/get.go b/pkg/server/workspaces/get.go deleted file mode 100644 index 3b705e2461..0000000000 --- a/pkg/server/workspaces/get.go +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package workspaces - -import ( - "context" - "errors" - "fmt" - "time" - - "github.com/daytonaio/daytona/pkg/provider" - "github.com/daytonaio/daytona/pkg/provisioner" - "github.com/daytonaio/daytona/pkg/server/workspaces/dto" - log "github.com/sirupsen/logrus" -) - -func (s *WorkspaceService) GetWorkspace(ctx context.Context, workspaceId string, verbose bool) (*dto.WorkspaceDTO, error) { - ws, err := s.workspaceStore.Find(workspaceId) - if err != nil { - return nil, ErrWorkspaceNotFound - } - - response := dto.WorkspaceDTO{ - Workspace: *ws, - } - - if !verbose { - return &response, nil - } - - target, err := s.targetStore.Find(&provider.TargetFilter{Name: &ws.Target}) - if err != nil { - return nil, err - } - - ctx, cancel := context.WithTimeout(ctx, 5*time.Second) - defer cancel() - - resultCh := make(chan provisioner.InfoResult, 1) - - go func() { - workspaceInfo, err := s.provisioner.GetWorkspaceInfo(ctx, ws, target) - resultCh <- provisioner.InfoResult{Info: workspaceInfo, Err: err} - }() - - select { - case res := <-resultCh: - if res.Err != nil { - log.Error(fmt.Errorf("failed to get workspace info for %s: %v", ws.Name, res.Err)) - return nil, res.Err - } - - response.Info = res.Info - case <-ctx.Done(): - if errors.Is(ctx.Err(), context.DeadlineExceeded) { - log.Warn(fmt.Sprintf("timeout getting workspace info for %s", ws.Name)) - } else { - log.Warn(fmt.Sprintf("cancelled getting workspace info for %s", ws.Name)) - } - } - - return &response, nil -} diff --git a/pkg/server/workspaces/labels.go b/pkg/server/workspaces/labels.go new file mode 100644 index 0000000000..d4fbe607df --- /dev/null +++ b/pkg/server/workspaces/labels.go @@ -0,0 +1,49 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package workspaces + +import ( + "context" + + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/services" + "github.com/daytonaio/daytona/pkg/telemetry" + log "github.com/sirupsen/logrus" +) + +func (s *WorkspaceService) UpdateLabels(ctx context.Context, workspaceId string, labels map[string]string) (*services.WorkspaceDTO, error) { + w, err := s.workspaceStore.Find(ctx, workspaceId) + if err != nil { + return nil, s.handleUpdateLabelsError(ctx, w, err) + } + + w.Labels = labels + + if err := s.workspaceStore.Save(ctx, w); err != nil { + return nil, s.handleUpdateLabelsError(ctx, w, err) + } + + return &services.WorkspaceDTO{Workspace: *w, State: w.GetState()}, s.handleUpdateLabelsError(ctx, w, nil) +} + +func (s *WorkspaceService) handleUpdateLabelsError(ctx context.Context, w *models.Workspace, err error) error { + if !telemetry.TelemetryEnabled(ctx) { + return err + } + + clientId := telemetry.ClientId(ctx) + + eventName := telemetry.WorkspaceEventLabelsUpdated + if err != nil { + eventName = telemetry.WorkspaceEventLabelsUpdateFailed + } + event := telemetry.NewWorkspaceEvent(eventName, w, err, nil) + + telemetryError := s.trackTelemetryEvent(event, clientId) + if telemetryError != nil { + log.Trace(telemetryError) + } + + return err +} diff --git a/pkg/server/workspaces/list.go b/pkg/server/workspaces/list.go index 996bb6bc39..0660acb6f9 100644 --- a/pkg/server/workspaces/list.go +++ b/pkg/server/workspaces/list.go @@ -5,70 +5,45 @@ package workspaces import ( "context" - "errors" - "fmt" - "sync" - "time" - "github.com/daytonaio/daytona/pkg/provider" - "github.com/daytonaio/daytona/pkg/provisioner" - "github.com/daytonaio/daytona/pkg/server/workspaces/dto" - log "github.com/sirupsen/logrus" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/services" ) -func (s *WorkspaceService) ListWorkspaces(ctx context.Context, verbose bool) ([]dto.WorkspaceDTO, error) { - workspaces, err := s.workspaceStore.List() +func (s *WorkspaceService) List(ctx context.Context, params services.WorkspaceRetrievalParams) ([]services.WorkspaceDTO, error) { + workspaces, err := s.workspaceStore.List(ctx) if err != nil { return nil, err } - var wg sync.WaitGroup - response := []dto.WorkspaceDTO{} + response := []services.WorkspaceDTO{} - for i, w := range workspaces { - response = append(response, dto.WorkspaceDTO{Workspace: *w}) - if !verbose { + for _, ws := range workspaces { + state := ws.GetState() + + if !matchesLabels(ws, params.Labels) || (state.Name == models.ResourceStateNameDeleted && !params.ShowDeleted) { continue } - wg.Add(1) - go func(i int) { - defer wg.Done() - - target, err := s.targetStore.Find(&provider.TargetFilter{Name: &w.Target}) - if err != nil { - log.Error(fmt.Errorf("failed to get target for %s", w.Target)) - return - } - - ctx, cancel := context.WithTimeout(ctx, 5*time.Second) - defer cancel() - - resultCh := make(chan provisioner.InfoResult, 1) + response = append(response, services.WorkspaceDTO{ + Workspace: *ws, + State: state, + }) + } - go func() { - workspaceInfo, err := s.provisioner.GetWorkspaceInfo(ctx, w, target) - resultCh <- provisioner.InfoResult{Info: workspaceInfo, Err: err} - }() + return response, nil +} - select { - case res := <-resultCh: - if res.Err != nil { - log.Error(fmt.Errorf("failed to get workspace info for %s: %v", w.Name, res.Err)) - return - } +func matchesLabels(w *models.Workspace, labels map[string]string) bool { + if labels == nil { + return true + } - response[i].Info = res.Info - case <-ctx.Done(): - if errors.Is(ctx.Err(), context.DeadlineExceeded) { - log.Warn(fmt.Sprintf("timeout getting workspace info for %s", w.Name)) - } else { - log.Warn(fmt.Sprintf("cancelled getting workspace info for %s", w.Name)) - } - } - }(i) + for k, v := range labels { + if w.Labels[k] != v { + return false + } } - wg.Wait() - return response, nil + return true } diff --git a/pkg/server/workspaces/metadata.go b/pkg/server/workspaces/metadata.go new file mode 100644 index 0000000000..55203202fa --- /dev/null +++ b/pkg/server/workspaces/metadata.go @@ -0,0 +1,23 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package workspaces + +import ( + "context" + + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/stores" +) + +func (s *WorkspaceService) UpdateMetadata(ctx context.Context, workspaceId string, metadata *models.WorkspaceMetadata) (*models.WorkspaceMetadata, error) { + m, err := s.workspaceMetadataStore.Find(ctx, workspaceId) + if err != nil { + return nil, stores.ErrWorkspaceMetadataNotFound + } + + m.GitStatus = metadata.GitStatus + m.Uptime = metadata.Uptime + m.UpdatedAt = metadata.UpdatedAt + return m, s.workspaceMetadataStore.Save(ctx, m) +} diff --git a/pkg/server/workspaces/remove.go b/pkg/server/workspaces/remove.go deleted file mode 100644 index bda3117d2b..0000000000 --- a/pkg/server/workspaces/remove.go +++ /dev/null @@ -1,153 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package workspaces - -import ( - "context" - "fmt" - - "github.com/daytonaio/daytona/pkg/logs" - "github.com/daytonaio/daytona/pkg/provider" - "github.com/daytonaio/daytona/pkg/telemetry" - log "github.com/sirupsen/logrus" -) - -func (s *WorkspaceService) RemoveWorkspace(ctx context.Context, workspaceId string) error { - workspace, err := s.workspaceStore.Find(workspaceId) - if err != nil { - return ErrWorkspaceNotFound - } - - log.Infof("Destroying workspace %s", workspace.Id) - - target, err := s.targetStore.Find(&provider.TargetFilter{Name: &workspace.Target}) - if err != nil { - return err - } - - for _, project := range workspace.Projects { - // todo: go routines - err := s.provisioner.DestroyProject(project, target) - if err != nil { - return err - } - } - - err = s.provisioner.DestroyWorkspace(workspace, target) - if err != nil { - return err - } - - // Should not fail the whole operation if the API key cannot be revoked - err = s.apiKeyService.Revoke(workspace.Id) - if err != nil { - log.Error(err) - } - - for _, project := range workspace.Projects { - err := s.apiKeyService.Revoke(fmt.Sprintf("%s/%s", workspace.Id, project.Name)) - if err != nil { - // Should not fail the whole operation if the API key cannot be revoked - log.Error(err) - } - projectLogger := s.loggerFactory.CreateProjectLogger(workspace.Id, project.Name, logs.LogSourceServer) - err = projectLogger.Cleanup() - if err != nil { - // Should not fail the whole operation if the project logger cannot be cleaned up - log.Error(err) - } - } - - logger := s.loggerFactory.CreateWorkspaceLogger(workspace.Id, logs.LogSourceServer) - err = logger.Cleanup() - if err != nil { - // Should not fail the whole operation if the workspace logger cannot be cleaned up - log.Error(err) - } - - err = s.workspaceStore.Delete(workspace) - - if !telemetry.TelemetryEnabled(ctx) { - return err - } - - clientId := telemetry.ClientId(ctx) - - telemetryProps := telemetry.NewWorkspaceEventProps(ctx, workspace, target) - event := telemetry.ServerEventWorkspaceDestroyed - if err != nil { - telemetryProps["error"] = err.Error() - event = telemetry.ServerEventWorkspaceDestroyError - } - telemetryError := s.telemetryService.TrackServerEvent(event, clientId, telemetryProps) - if telemetryError != nil { - log.Trace(telemetryError) - } - - return err -} - -// ForceRemoveWorkspace ignores provider errors and makes sure the workspace is removed from storage. -func (s *WorkspaceService) ForceRemoveWorkspace(ctx context.Context, workspaceId string) error { - workspace, err := s.workspaceStore.Find(workspaceId) - if err != nil { - return ErrWorkspaceNotFound - } - - log.Infof("Destroying workspace %s", workspace.Id) - - target, _ := s.targetStore.Find(&provider.TargetFilter{Name: &workspace.Target}) - - for _, project := range workspace.Projects { - // todo: go routines - err := s.provisioner.DestroyProject(project, target) - if err != nil { - log.Error(err) - } - } - - err = s.provisioner.DestroyWorkspace(workspace, target) - if err != nil { - log.Error(err) - } - - err = s.apiKeyService.Revoke(workspace.Id) - if err != nil { - log.Error(err) - } - - for _, project := range workspace.Projects { - err := s.apiKeyService.Revoke(fmt.Sprintf("%s/%s", workspace.Id, project.Name)) - if err != nil { - log.Error(err) - } - - projectLogger := s.loggerFactory.CreateProjectLogger(workspace.Id, project.Name, logs.LogSourceServer) - err = projectLogger.Cleanup() - if err != nil { - log.Error(err) - } - } - - err = s.workspaceStore.Delete(workspace) - - if !telemetry.TelemetryEnabled(ctx) { - return err - } - - clientId := telemetry.ClientId(ctx) - - telemetryProps := telemetry.NewWorkspaceEventProps(ctx, workspace, target) - event := telemetry.ServerEventWorkspaceDestroyed - if err != nil { - telemetryProps["error"] = err.Error() - event = telemetry.ServerEventWorkspaceDestroyError - } - telemetryError := s.telemetryService.TrackServerEvent(event, clientId, telemetryProps) - if telemetryError != nil { - log.Trace(telemetryError) - } - - return err -} diff --git a/pkg/server/workspaces/restart.go b/pkg/server/workspaces/restart.go new file mode 100644 index 0000000000..9a114a0cb9 --- /dev/null +++ b/pkg/server/workspaces/restart.go @@ -0,0 +1,47 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package workspaces + +import ( + "context" + + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/stores" + "github.com/daytonaio/daytona/pkg/telemetry" + log "github.com/sirupsen/logrus" +) + +func (s *WorkspaceService) Restart(ctx context.Context, workspaceId string) error { + w, err := s.workspaceStore.Find(ctx, workspaceId) + if err != nil { + return s.handleRestartError(ctx, w, stores.ErrWorkspaceNotFound) + } + + err = s.createJob(ctx, w.Id, w.Target.TargetConfig.ProviderInfo.RunnerId, models.JobActionRestart) + if err != nil { + return s.handleRestartError(ctx, w, err) + } + + return s.handleRestartError(ctx, w, err) +} + +func (s *WorkspaceService) handleRestartError(ctx context.Context, w *models.Workspace, err error) error { + if !telemetry.TelemetryEnabled(ctx) { + return err + } + + clientId := telemetry.ClientId(ctx) + + eventName := telemetry.WorkspaceEventLifecycleRestarted + if err != nil { + eventName = telemetry.WorkspaceEventLifecycleRestartFailed + } + event := telemetry.NewWorkspaceEvent(eventName, w, err, nil) + + telemetryError := s.trackTelemetryEvent(event, clientId) + if telemetryError != nil { + log.Trace(telemetryError) + } + return err +} diff --git a/pkg/server/workspaces/service.go b/pkg/server/workspaces/service.go index 21a131e1f4..f6e4e1cf64 100644 --- a/pkg/server/workspaces/service.go +++ b/pkg/server/workspaces/service.go @@ -5,121 +5,114 @@ package workspaces import ( "context" - "errors" "io" + "github.com/daytonaio/daytona/pkg/gitprovider" "github.com/daytonaio/daytona/pkg/logs" - "github.com/daytonaio/daytona/pkg/provider" - "github.com/daytonaio/daytona/pkg/provisioner" - "github.com/daytonaio/daytona/pkg/server/apikeys" - "github.com/daytonaio/daytona/pkg/server/builds" - "github.com/daytonaio/daytona/pkg/server/containerregistries" - "github.com/daytonaio/daytona/pkg/server/gitproviders" - "github.com/daytonaio/daytona/pkg/server/projectconfig" - "github.com/daytonaio/daytona/pkg/server/workspaces/dto" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/services" + "github.com/daytonaio/daytona/pkg/stores" "github.com/daytonaio/daytona/pkg/telemetry" - "github.com/daytonaio/daytona/pkg/workspace" - "github.com/daytonaio/daytona/pkg/workspace/project" ) -type IWorkspaceService interface { - CreateWorkspace(ctx context.Context, req dto.CreateWorkspaceDTO) (*workspace.Workspace, error) - GetWorkspace(ctx context.Context, workspaceId string, verbose bool) (*dto.WorkspaceDTO, error) - GetWorkspaceLogReader(workspaceId string) (io.Reader, error) - GetProjectLogReader(workspaceId, projectName string) (io.Reader, error) - ListWorkspaces(ctx context.Context, verbose bool) ([]dto.WorkspaceDTO, error) - RemoveWorkspace(ctx context.Context, workspaceId string) error - ForceRemoveWorkspace(ctx context.Context, workspaceId string) error - SetProjectState(workspaceId string, projectName string, state *project.ProjectState) (*workspace.Workspace, error) - StartProject(ctx context.Context, workspaceId string, projectName string) error - StartWorkspace(ctx context.Context, workspaceId string) error - StopProject(ctx context.Context, workspaceId string, projectName string) error - StopWorkspace(ctx context.Context, workspaceId string) error -} +type WorkspaceServiceConfig struct { + WorkspaceStore stores.WorkspaceStore + WorkspaceMetadataStore stores.WorkspaceMetadataStore -type targetStore interface { - Find(filter *provider.TargetFilter) (*provider.ProviderTarget, error) -} + FindTarget func(ctx context.Context, targetId string) (*models.Target, error) + FindContainerRegistry func(ctx context.Context, image string, envVars map[string]string) *models.ContainerRegistry + FindCachedBuild func(ctx context.Context, w *models.Workspace) (*models.CachedBuild, error) + CreateApiKey func(ctx context.Context, name string) (string, error) + DeleteApiKey func(ctx context.Context, name string) error + ListGitProviderConfigs func(ctx context.Context, repoUrl string) ([]*models.GitProviderConfig, error) + FindGitProviderConfig func(ctx context.Context, id string) (*models.GitProviderConfig, error) + GetLastCommitSha func(ctx context.Context, repo *gitprovider.GitRepository) (string, error) + CreateJob func(ctx context.Context, workspaceId string, runnerId string, action models.JobAction) error + TrackTelemetryEvent func(event telemetry.Event, clientId string) error -type WorkspaceServiceConfig struct { - WorkspaceStore workspace.Store - TargetStore targetStore - ContainerRegistryService containerregistries.IContainerRegistryService - BuildService builds.IBuildService - ProjectConfigService projectconfig.IProjectConfigService - ServerApiUrl string - ServerUrl string - ServerVersion string - Provisioner provisioner.IProvisioner - DefaultProjectImage string - DefaultProjectUser string - BuilderImage string - ApiKeyService apikeys.IApiKeyService - LoggerFactory logs.LoggerFactory - GitProviderService gitproviders.IGitProviderService - TelemetryService telemetry.TelemetryService + LoggerFactory logs.ILoggerFactory + ServerApiUrl string + ServerUrl string + ServerVersion string + DefaultWorkspaceImage string + DefaultWorkspaceUser string } -func NewWorkspaceService(config WorkspaceServiceConfig) IWorkspaceService { +func NewWorkspaceService(config WorkspaceServiceConfig) services.IWorkspaceService { return &WorkspaceService{ - workspaceStore: config.WorkspaceStore, - targetStore: config.TargetStore, - containerRegistryService: config.ContainerRegistryService, - buildService: config.BuildService, - projectConfigService: config.ProjectConfigService, - serverApiUrl: config.ServerApiUrl, - serverUrl: config.ServerUrl, - serverVersion: config.ServerVersion, - defaultProjectImage: config.DefaultProjectImage, - defaultProjectUser: config.DefaultProjectUser, - provisioner: config.Provisioner, - loggerFactory: config.LoggerFactory, - apiKeyService: config.ApiKeyService, - gitProviderService: config.GitProviderService, - telemetryService: config.TelemetryService, - builderImage: config.BuilderImage, + workspaceStore: config.WorkspaceStore, + workspaceMetadataStore: config.WorkspaceMetadataStore, + + findTarget: config.FindTarget, + findContainerRegistry: config.FindContainerRegistry, + findCachedBuild: config.FindCachedBuild, + createApiKey: config.CreateApiKey, + deleteApiKey: config.DeleteApiKey, + listGitProviderConfigs: config.ListGitProviderConfigs, + findGitProviderConfig: config.FindGitProviderConfig, + getLastCommitSha: config.GetLastCommitSha, + createJob: config.CreateJob, + trackTelemetryEvent: config.TrackTelemetryEvent, + + serverApiUrl: config.ServerApiUrl, + serverUrl: config.ServerUrl, + serverVersion: config.ServerVersion, + defaultWorkspaceImage: config.DefaultWorkspaceImage, + defaultWorkspaceUser: config.DefaultWorkspaceUser, + loggerFactory: config.LoggerFactory, } } type WorkspaceService struct { - workspaceStore workspace.Store - targetStore targetStore - containerRegistryService containerregistries.IContainerRegistryService - buildService builds.IBuildService - projectConfigService projectconfig.IProjectConfigService - provisioner provisioner.IProvisioner - apiKeyService apikeys.IApiKeyService - serverApiUrl string - serverUrl string - serverVersion string - defaultProjectImage string - defaultProjectUser string - builderImage string - loggerFactory logs.LoggerFactory - gitProviderService gitproviders.IGitProviderService - telemetryService telemetry.TelemetryService + workspaceStore stores.WorkspaceStore + workspaceMetadataStore stores.WorkspaceMetadataStore + + findTarget func(ctx context.Context, targetId string) (*models.Target, error) + findContainerRegistry func(ctx context.Context, image string, envVars map[string]string) *models.ContainerRegistry + findCachedBuild func(ctx context.Context, w *models.Workspace) (*models.CachedBuild, error) + createApiKey func(ctx context.Context, name string) (string, error) + deleteApiKey func(ctx context.Context, name string) error + listGitProviderConfigs func(ctx context.Context, repoUrl string) ([]*models.GitProviderConfig, error) + findGitProviderConfig func(ctx context.Context, id string) (*models.GitProviderConfig, error) + getLastCommitSha func(ctx context.Context, repo *gitprovider.GitRepository) (string, error) + createJob func(ctx context.Context, workspaceId string, runnerId string, action models.JobAction) error + trackTelemetryEvent func(event telemetry.Event, clientId string) error + + serverApiUrl string + serverUrl string + serverVersion string + defaultWorkspaceImage string + defaultWorkspaceUser string + loggerFactory logs.ILoggerFactory } -func (s *WorkspaceService) SetProjectState(workspaceId, projectName string, state *project.ProjectState) (*workspace.Workspace, error) { - ws, err := s.workspaceStore.Find(workspaceId) - if err != nil { - return nil, err - } +func (s *WorkspaceService) GetWorkspaceLogReader(ctx context.Context, workspaceId string) (io.Reader, error) { + return s.loggerFactory.CreateLogReader(workspaceId) +} - for _, project := range ws.Projects { - if project.Name == projectName { - project.State = state - return ws, s.workspaceStore.Save(ws) - } +func (s *WorkspaceService) GetWorkspaceLogWriter(ctx context.Context, workspaceId string) (io.WriteCloser, error) { + return s.loggerFactory.CreateLogWriter(workspaceId) +} + +func (s *WorkspaceService) UpdateProviderMetadata(ctx context.Context, workspaceId, metadata string) error { + w, err := s.workspaceStore.Find(ctx, workspaceId) + if err != nil { + return err } - return nil, errors.New("project not found") + w.ProviderMetadata = &metadata + return s.workspaceStore.Save(ctx, w) } -func (s *WorkspaceService) GetWorkspaceLogReader(workspaceId string) (io.Reader, error) { - return s.loggerFactory.CreateWorkspaceLogReader(workspaceId) -} +func (s *WorkspaceService) UpdateLastJob(ctx context.Context, workspaceId, jobId string) error { + w, err := s.workspaceStore.Find(ctx, workspaceId) + if err != nil { + return err + } + + w.LastJobId = &jobId + // Make sure the old relation doesn't get saved to the store + w.LastJob = nil -func (s *WorkspaceService) GetProjectLogReader(workspaceId, projectName string) (io.Reader, error) { - return s.loggerFactory.CreateProjectLogReader(workspaceId, projectName) + return s.workspaceStore.Save(ctx, w) } diff --git a/pkg/server/workspaces/service_test.go b/pkg/server/workspaces/service_test.go index d0d01d07c2..5542f36622 100644 --- a/pkg/server/workspaces/service_test.go +++ b/pkg/server/workspaces/service_test.go @@ -5,25 +5,20 @@ package workspaces_test import ( "context" - "fmt" "testing" - "time" - t_targets "github.com/daytonaio/daytona/internal/testing/provider/targets" + "github.com/daytonaio/daytona/internal/testing/job" + t_targets "github.com/daytonaio/daytona/internal/testing/server/targets" + "github.com/daytonaio/daytona/internal/testing/server/targets/mocks" t_workspaces "github.com/daytonaio/daytona/internal/testing/server/workspaces" - "github.com/daytonaio/daytona/internal/testing/server/workspaces/mocks" "github.com/daytonaio/daytona/internal/util" - "github.com/daytonaio/daytona/pkg/apikey" - "github.com/daytonaio/daytona/pkg/containerregistry" "github.com/daytonaio/daytona/pkg/gitprovider" "github.com/daytonaio/daytona/pkg/logs" - "github.com/daytonaio/daytona/pkg/provider" - "github.com/daytonaio/daytona/pkg/provisioner" + "github.com/daytonaio/daytona/pkg/models" "github.com/daytonaio/daytona/pkg/server/workspaces" - "github.com/daytonaio/daytona/pkg/server/workspaces/dto" + "github.com/daytonaio/daytona/pkg/services" + "github.com/daytonaio/daytona/pkg/stores" "github.com/daytonaio/daytona/pkg/telemetry" - "github.com/daytonaio/daytona/pkg/workspace" - "github.com/daytonaio/daytona/pkg/workspace/project" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" ) @@ -31,22 +26,14 @@ import ( const serverApiUrl = "http://localhost:3986" const serverUrl = "http://localhost:3987" const serverVersion = "0.0.0-test" -const defaultProjectUser = "daytona" -const defaultProjectImage = "daytonaio/workspace-project:latest" +const defaultWorkspaceUser = "daytona" +const defaultWorkspaceImage = "daytonaio/workspace-project:latest" -var target = provider.ProviderTarget{ - Name: "test-target", - ProviderInfo: provider.ProviderInfo{ - Name: "test-provider", - Version: "test", - }, - Options: "test-options", -} var gitProviderConfigId = "github" var baseApiUrl = "https://api.github.com" -var gitProviderConfig = gitprovider.GitProviderConfig{ +var gitProviderConfig = models.GitProviderConfig{ Id: "github", ProviderId: gitProviderConfigId, Alias: "test-alias", @@ -55,339 +42,304 @@ var gitProviderConfig = gitprovider.GitProviderConfig{ BaseApiUrl: &baseApiUrl, } -var createWorkspaceDto = dto.CreateWorkspaceDTO{ - Name: "test", - Id: "test", - Target: target.Name, - Projects: []dto.CreateProjectDTO{ - { - Name: "project1", - GitProviderConfigId: &gitProviderConfig.Id, - Source: dto.CreateProjectSourceDTO{ - Repository: &gitprovider.GitRepository{ - Id: "123", - Url: "https://github.com/daytonaio/daytona", - Name: "daytona", - Branch: "main", - Sha: "sha1", - }, - }, - Image: util.Pointer(defaultProjectImage), - User: util.Pointer(defaultProjectUser), - }, +var tc = &models.TargetConfig{ + Name: "tc-test", + ProviderInfo: models.ProviderInfo{ + Name: "test-provider", + Version: "test", }, + Options: "test-options", + Deleted: false, +} + +var tg = &models.Target{ + Id: "123", + Name: "test", + TargetConfigId: tc.Id, + TargetConfig: *tc, } -var workspaceInfo = workspace.WorkspaceInfo{ - Name: createWorkspaceDto.Name, - ProviderMetadata: "provider-metadata-test", - Projects: []*project.ProjectInfo{ - { - Name: createWorkspaceDto.Projects[0].Name, - Created: "1 min ago", - IsRunning: true, - ProviderMetadata: "provider-metadata-test", - WorkspaceId: createWorkspaceDto.Id, +var createWorkspaceDTO = services.CreateWorkspaceDTO{ + Id: "123", + Name: "workspace1", + GitProviderConfigId: &gitProviderConfig.Id, + Source: services.CreateWorkspaceSourceDTO{ + Repository: &gitprovider.GitRepository{ + Id: "123", + Url: "https://github.com/daytonaio/daytona", + Name: "daytona", + Branch: "main", + Sha: "sha1", }, }, + Image: util.Pointer(defaultWorkspaceImage), + User: util.Pointer(defaultWorkspaceUser), + TargetId: tg.Id, } -func TestWorkspaceService(t *testing.T) { - ctx := context.Background() - ctx = context.WithValue(ctx, telemetry.CLIENT_ID_CONTEXT_KEY, "test") +var ws = &models.Workspace{ + Id: "123", + Name: "workspace1", + ApiKey: createWorkspaceDTO.Name, + GitProviderConfigId: &gitProviderConfig.Id, + Repository: &gitprovider.GitRepository{ + Id: "123", + Url: "https://github.com/daytonaio/daytona", + Name: "daytona", + Branch: "main", + Sha: "sha1", + }, + Image: defaultWorkspaceImage, + User: defaultWorkspaceUser, + TargetId: tg.Id, +} - workspaceStore := t_workspaces.NewInMemoryWorkspaceStore() +func TestWorkspaceService(t *testing.T) { + ws.EnvVars = workspaces.GetWorkspaceEnvVars(ws, workspaces.WorkspaceEnvVarParams{ + ApiUrl: serverApiUrl, + ServerUrl: serverUrl, + ClientId: "test-client-id", + }) - containerRegistryService := mocks.NewMockContainerRegistryService() + ctx := context.Background() + ctx = context.WithValue(ctx, telemetry.CLIENT_ID_CONTEXT_KEY, "test-client-id") - projectConfigService := mocks.NewMockProjectConfigService() + jobStore := job.NewInMemoryJobStore() - targetStore := t_targets.NewInMemoryTargetStore() - err := targetStore.Save(&target) + targetStore := t_targets.NewInMemoryTargetStore(jobStore) + err := targetStore.Save(ctx, tg) require.Nil(t, err) + workspaceStore := t_workspaces.NewInMemoryWorkspaceStore(jobStore) + metadataStore := t_workspaces.NewInMemoryWorkspaceMetadataStore() + apiKeyService := mocks.NewMockApiKeyService() gitProviderService := mocks.NewMockGitProviderService() - mockProvisioner := mocks.NewMockProvisioner() - wsLogsDir := t.TempDir() - buildLogsDir := t.TempDir() + tgLogsDir := t.TempDir() service := workspaces.NewWorkspaceService(workspaces.WorkspaceServiceConfig{ - WorkspaceStore: workspaceStore, - TargetStore: targetStore, - ServerApiUrl: serverApiUrl, - ServerUrl: serverUrl, - ServerVersion: serverVersion, - ContainerRegistryService: containerRegistryService, - ProjectConfigService: projectConfigService, - DefaultProjectImage: defaultProjectImage, - DefaultProjectUser: defaultProjectUser, - BuilderImage: defaultProjectImage, - ApiKeyService: apiKeyService, - Provisioner: mockProvisioner, - LoggerFactory: logs.NewLoggerFactory(&wsLogsDir, &buildLogsDir), - GitProviderService: gitProviderService, + WorkspaceMetadataStore: metadataStore, + FindTarget: func(ctx context.Context, targetId string) (*models.Target, error) { + t, err := targetStore.Find(ctx, &stores.TargetFilter{IdOrName: &targetId}) + if err != nil { + return nil, err + } + return t, nil + }, + FindContainerRegistry: func(ctx context.Context, image string, envVars map[string]string) *models.ContainerRegistry { + return services.EnvironmentVariables(envVars).FindContainerRegistryByImageName(image) + }, + FindCachedBuild: func(ctx context.Context, w *models.Workspace) (*models.CachedBuild, error) { + return nil, nil + }, + CreateApiKey: func(ctx context.Context, name string) (string, error) { + return apiKeyService.Create(models.ApiKeyTypeWorkspace, name) + }, + DeleteApiKey: func(ctx context.Context, name string) error { + return apiKeyService.Delete(name) + }, + ListGitProviderConfigs: func(ctx context.Context, repoUrl string) ([]*models.GitProviderConfig, error) { + return gitProviderService.ListConfigsForUrl(repoUrl) + }, + FindGitProviderConfig: func(ctx context.Context, id string) (*models.GitProviderConfig, error) { + return gitProviderService.FindConfig(id) + }, + GetLastCommitSha: func(ctx context.Context, repo *gitprovider.GitRepository) (string, error) { + return gitProviderService.GetLastCommitSha(repo) + }, + TrackTelemetryEvent: func(event telemetry.Event, clientId string) error { + return nil + }, + WorkspaceStore: workspaceStore, + ServerApiUrl: serverApiUrl, + ServerUrl: serverUrl, + DefaultWorkspaceImage: defaultWorkspaceImage, + DefaultWorkspaceUser: defaultWorkspaceUser, + LoggerFactory: logs.NewLoggerFactory(logs.LoggerFactoryConfig{LogsDir: tgLogsDir}), + CreateJob: func(ctx context.Context, workspaceId, runnerId string, action models.JobAction) error { + return jobStore.Save(ctx, &models.Job{ + Id: workspaceId, + ResourceId: workspaceId, + RunnerId: util.Pointer(runnerId), + ResourceType: models.ResourceTypeWorkspace, + Action: action, + State: models.JobStateSuccess, + }) + }, }) t.Run("CreateWorkspace", func(t *testing.T) { - var containerRegistry *containerregistry.ContainerRegistry + gitProviderService.On("GetLastCommitSha", createWorkspaceDTO.Source.Repository).Return("123", nil) + + apiKeyService.On("Create", models.ApiKeyTypeWorkspace, createWorkspaceDTO.Id).Return(createWorkspaceDTO.Name, nil) + + ws := &models.Workspace{ + Id: createWorkspaceDTO.Id, + Name: createWorkspaceDTO.Name, + Image: *createWorkspaceDTO.Image, + User: *createWorkspaceDTO.User, + BuildConfig: createWorkspaceDTO.BuildConfig, + Repository: createWorkspaceDTO.Source.Repository, + ApiKey: createWorkspaceDTO.Name, + GitProviderConfigId: createWorkspaceDTO.GitProviderConfigId, + TargetId: createWorkspaceDTO.Id, + } + + ws.EnvVars = workspaces.GetWorkspaceEnvVars(ws, workspaces.WorkspaceEnvVarParams{ + ApiUrl: serverApiUrl, + ServerUrl: serverUrl, + ServerVersion: serverVersion, + ClientId: "test", + }) - containerRegistryService.On("FindByImageName", defaultProjectImage).Return(containerRegistry, containerregistry.ErrContainerRegistryNotFound) + gitProviderService.On("FindConfig", "github").Return(&gitProviderConfig, nil) - mockProvisioner.On("CreateWorkspace", mock.Anything, &target).Return(nil) - mockProvisioner.On("StartWorkspace", mock.Anything, &target).Return(nil) + workspace, err := service.Create(ctx, createWorkspaceDTO) - apiKeyService.On("Generate", apikey.ApiKeyTypeWorkspace, createWorkspaceDto.Id).Return(createWorkspaceDto.Id, nil) - gitProviderService.On("GetLastCommitSha", createWorkspaceDto.Projects[0].Source.Repository).Return("123", nil) + require.Nil(t, err) + require.NotNil(t, workspace) - for _, project := range createWorkspaceDto.Projects { - apiKeyService.On("Generate", apikey.ApiKeyTypeProject, fmt.Sprintf("%s/%s", createWorkspaceDto.Id, project.Name)).Return(project.Name, nil) - } + workspaceEquals(t, &services.WorkspaceDTO{Workspace: *ws}, workspace) + + job, err := jobStore.Find(ctx, &stores.JobFilter{ResourceId: &ws.Id}) + require.Nil(t, err) + require.Equal(t, job.ResourceType, models.ResourceTypeWorkspace) + + ws.EnvVars = nil + }) - proj := &project.Project{ - Name: createWorkspaceDto.Projects[0].Name, - Image: *createWorkspaceDto.Projects[0].Image, - User: *createWorkspaceDto.Projects[0].User, - BuildConfig: createWorkspaceDto.Projects[0].BuildConfig, - Repository: createWorkspaceDto.Projects[0].Source.Repository, - ApiKey: createWorkspaceDto.Projects[0].Name, - GitProviderConfigId: createWorkspaceDto.Projects[0].GitProviderConfigId, - WorkspaceId: createWorkspaceDto.Id, - Target: createWorkspaceDto.Target, + t.Run("UpdateLabels", func(t *testing.T) { + labels := map[string]string{ + "test": "label", } - proj.EnvVars = project.GetProjectEnvVars(proj, project.ProjectEnvVarParams{ - ApiUrl: serverApiUrl, - ServerUrl: serverUrl, - ServerVersion: serverVersion, - ClientId: "test", - }, false) - - mockProvisioner.On("CreateProject", provisioner.ProjectParams{ - Project: proj, - Target: &target, - ContainerRegistry: containerRegistry, - GitProviderConfig: &gitProviderConfig, - BuilderImage: defaultProjectImage, - BuilderImageContainerRegistry: containerRegistry, - }).Return(nil) - mockProvisioner.On("StartProject", provisioner.ProjectParams{ - Project: proj, - Target: &target, - ContainerRegistry: containerRegistry, - GitProviderConfig: &gitProviderConfig, - BuilderImage: defaultProjectImage, - BuilderImageContainerRegistry: containerRegistry, - }).Return(nil) - - gitProviderService.On("GetConfig", "github").Return(&gitProviderConfig, nil) - - workspace, err := service.CreateWorkspace(ctx, createWorkspaceDto) + workspace, err := service.UpdateLabels(ctx, createWorkspaceDTO.Id, labels) require.Nil(t, err) require.NotNil(t, workspace) - workspaceEquals(t, createWorkspaceDto, workspace, defaultProjectImage) + require.Equal(t, labels, workspace.Labels) }) t.Run("CreateWorkspace fails when workspace already exists", func(t *testing.T) { - _, err := service.CreateWorkspace(ctx, createWorkspaceDto) + _, err := service.Create(ctx, createWorkspaceDTO) require.NotNil(t, err) - require.Equal(t, workspaces.ErrWorkspaceAlreadyExists, err) + require.Equal(t, services.ErrWorkspaceAlreadyExists, err) }) t.Run("CreateWorkspace fails name validation", func(t *testing.T) { - invalidWorkspaceRequest := createWorkspaceDto + invalidWorkspaceRequest := createWorkspaceDTO invalidWorkspaceRequest.Name = "invalid name" - _, err := service.CreateWorkspace(ctx, invalidWorkspaceRequest) + _, err := service.Create(ctx, invalidWorkspaceRequest) require.NotNil(t, err) - require.Equal(t, workspaces.ErrInvalidWorkspaceName, err) + require.Equal(t, services.ErrInvalidWorkspaceName, err) }) - t.Run("GetWorkspace", func(t *testing.T) { - mockProvisioner.On("GetWorkspaceInfo", mock.Anything, mock.Anything, &target).Return(&workspaceInfo, nil) - - workspace, err := service.GetWorkspace(ctx, createWorkspaceDto.Id, true) + t.Run("FindWorkspace", func(t *testing.T) { + w, err := service.Find(ctx, ws.Id, services.WorkspaceRetrievalParams{}) require.Nil(t, err) - require.NotNil(t, workspace) + require.NotNil(t, w) - workspaceDtoEquals(t, createWorkspaceDto, *workspace, workspaceInfo, defaultProjectImage, true) + workspaceDtoEquals(t, createWorkspaceDTO, *w, defaultWorkspaceImage) }) - t.Run("GetWorkspace fails when workspace not found", func(t *testing.T) { - _, err := service.GetWorkspace(ctx, "invalid-id", true) + t.Run("FindWorkspace fails when workspace not found", func(t *testing.T) { + _, err := service.Find(ctx, "invalid-id", services.WorkspaceRetrievalParams{}) require.NotNil(t, err) - require.Equal(t, workspaces.ErrWorkspaceNotFound, err) + require.Equal(t, stores.ErrWorkspaceNotFound, err) }) t.Run("ListWorkspaces", func(t *testing.T) { - verbose := false - mockProvisioner.On("GetWorkspaceInfo", mock.Anything, mock.Anything, &target).Return(&workspaceInfo, nil) - - workspaces, err := service.ListWorkspaces(ctx, verbose) - - require.Nil(t, err) - require.Len(t, workspaces, 1) - - workspace := workspaces[0] - - workspaceDtoEquals(t, createWorkspaceDto, workspace, workspaceInfo, defaultProjectImage, verbose) - }) - - t.Run("ListWorkspaces - verbose", func(t *testing.T) { - verbose := true - mockProvisioner.On("GetWorkspaceInfo", mock.Anything, mock.Anything, &target).Return(&workspaceInfo, nil) - - workspaces, err := service.ListWorkspaces(ctx, verbose) + workspaces, err := service.List(ctx, services.WorkspaceRetrievalParams{}) require.Nil(t, err) require.Len(t, workspaces, 1) - workspace := workspaces[0] - - workspaceDtoEquals(t, createWorkspaceDto, workspace, workspaceInfo, defaultProjectImage, verbose) + workspaceDtoEquals(t, createWorkspaceDTO, workspaces[0], defaultWorkspaceImage) }) t.Run("StartWorkspace", func(t *testing.T) { - mockProvisioner.On("StartWorkspace", mock.Anything, &target).Return(nil) - mockProvisioner.On("StartProject", mock.Anything).Return(nil) - - err := service.StartWorkspace(ctx, createWorkspaceDto.Id) - - require.Nil(t, err) - }) - - t.Run("StartProject", func(t *testing.T) { - mockProvisioner.On("StartWorkspace", mock.Anything, &target).Return(nil) - mockProvisioner.On("StartProject", mock.Anything).Return(nil) - - err := service.StartProject(ctx, createWorkspaceDto.Id, createWorkspaceDto.Projects[0].Name) + err := service.Start(ctx, createWorkspaceDTO.Id) require.Nil(t, err) }) t.Run("StopWorkspace", func(t *testing.T) { - mockProvisioner.On("StopWorkspace", mock.Anything, &target).Return(nil) - mockProvisioner.On("StopProject", mock.Anything, &target).Return(nil) - - err := service.StopWorkspace(ctx, createWorkspaceDto.Id) + err := service.Stop(ctx, createWorkspaceDTO.Id) require.Nil(t, err) }) - t.Run("StopProject", func(t *testing.T) { - mockProvisioner.On("StopWorkspace", mock.Anything, &target).Return(nil) - mockProvisioner.On("StopProject", mock.Anything, &target).Return(nil) - - err := service.StopProject(ctx, createWorkspaceDto.Id, createWorkspaceDto.Projects[0].Name) + t.Run("UpdateWorkspaceMetadata", func(t *testing.T) { + res, err := service.UpdateMetadata(ctx, createWorkspaceDTO.Id, &models.WorkspaceMetadata{ + Uptime: 10, + GitStatus: &models.GitStatus{ + CurrentBranch: "main", + }, + }) + require.Nil(t, err) require.Nil(t, err) + require.Equal(t, "main", res.GitStatus.CurrentBranch) }) - t.Run("RemoveWorkspace", func(t *testing.T) { - mockProvisioner.On("DestroyWorkspace", mock.Anything, &target).Return(nil) - mockProvisioner.On("DestroyProject", mock.Anything, &target).Return(nil) - apiKeyService.On("Revoke", mock.Anything).Return(nil) + t.Run("DeleteWorkspace", func(t *testing.T) { + apiKeyService.On("Delete", mock.Anything).Return(nil) - err := service.RemoveWorkspace(ctx, createWorkspaceDto.Id) + err := service.Delete(ctx, createWorkspaceDTO.Id) require.Nil(t, err) - _, err = service.GetWorkspace(ctx, createWorkspaceDto.Id, true) - require.Equal(t, workspaces.ErrWorkspaceNotFound, err) + _, err = service.Find(ctx, createWorkspaceDTO.Id, services.WorkspaceRetrievalParams{}) + require.Equal(t, services.ErrWorkspaceDeleted, err) }) - t.Run("ForceRemoveWorkspace", func(t *testing.T) { - err := workspaceStore.Save(&workspace.Workspace{Id: createWorkspaceDto.Id, Target: target.Name}) + t.Run("ForceDeleteWorkspace", func(t *testing.T) { + err := workspaceStore.Save(ctx, ws) require.Nil(t, err) - mockProvisioner.On("DestroyWorkspace", mock.Anything, &target).Return(nil) - mockProvisioner.On("DestroyProject", mock.Anything, &target).Return(nil) - apiKeyService.On("Revoke", mock.Anything).Return(nil) + apiKeyService.On("Delete", mock.Anything).Return(nil) - err = service.ForceRemoveWorkspace(ctx, createWorkspaceDto.Id) + err = service.ForceDelete(ctx, createWorkspaceDTO.Id) require.Nil(t, err) - _, err = service.GetWorkspace(ctx, createWorkspaceDto.Id, true) - require.Equal(t, workspaces.ErrWorkspaceNotFound, err) - }) - - t.Run("SetProjectState", func(t *testing.T) { - ws, err := service.CreateWorkspace(ctx, createWorkspaceDto) - require.Nil(t, err) - - projectName := ws.Projects[0].Name - updatedAt := time.Now().Format(time.RFC1123) - res, err := service.SetProjectState(ws.Id, projectName, &project.ProjectState{ - UpdatedAt: updatedAt, - Uptime: 10, - GitStatus: &project.GitStatus{ - CurrentBranch: "main", - }, - }) - require.Nil(t, err) - - project, err := res.GetProject(projectName) - require.Nil(t, err) - require.Equal(t, "main", project.State.GitStatus.CurrentBranch) + _, err = service.Find(ctx, createWorkspaceDTO.Id, services.WorkspaceRetrievalParams{}) + require.Equal(t, services.ErrWorkspaceDeleted, err) }) t.Cleanup(func() { apiKeyService.AssertExpectations(t) - mockProvisioner.AssertExpectations(t) }) } -func workspaceEquals(t *testing.T, req dto.CreateWorkspaceDTO, workspace *workspace.Workspace, projectImage string) { +func workspaceEquals(t *testing.T, ws1, ws2 *services.WorkspaceDTO) { t.Helper() - require.Equal(t, req.Id, workspace.Id) - require.Equal(t, req.Name, workspace.Name) - require.Equal(t, req.Target, workspace.Target) - - for i, project := range workspace.Projects { - require.Equal(t, req.Projects[i].Name, project.Name) - require.Equal(t, req.Projects[i].Source.Repository.Id, project.Repository.Id) - require.Equal(t, req.Projects[i].Source.Repository.Url, project.Repository.Url) - require.Equal(t, req.Projects[i].Source.Repository.Name, project.Repository.Name) - require.Equal(t, project.ApiKey, project.Name) - require.Equal(t, project.Target, req.Target) - require.Equal(t, project.Image, projectImage) - } + require.Equal(t, ws1.Id, ws2.Id) + require.Equal(t, ws1.Name, ws2.Name) + require.Equal(t, ws1.TargetId, ws2.TargetId) + require.Equal(t, ws1.Image, ws2.Image) + require.Equal(t, ws1.User, ws2.User) + require.Equal(t, ws1.ApiKey, ws2.ApiKey) + require.Equal(t, ws1.Repository.Id, ws2.Repository.Id) + require.Equal(t, ws1.Repository.Url, ws2.Repository.Url) + require.Equal(t, ws1.Repository.Name, ws2.Repository.Name) } -func workspaceDtoEquals(t *testing.T, req dto.CreateWorkspaceDTO, workspace dto.WorkspaceDTO, workspaceInfo workspace.WorkspaceInfo, projectImage string, verbose bool) { +func workspaceDtoEquals(t *testing.T, req services.CreateWorkspaceDTO, workspace services.WorkspaceDTO, workspaceImage string) { t.Helper() require.Equal(t, req.Id, workspace.Id) require.Equal(t, req.Name, workspace.Name) - require.Equal(t, req.Target, workspace.Target) - - if verbose { - require.Equal(t, workspace.Info.Name, workspaceInfo.Name) - require.Equal(t, workspace.Info.ProviderMetadata, workspaceInfo.ProviderMetadata) - } else { - require.Nil(t, workspace.Info) - } - - for i, project := range workspace.Projects { - require.Equal(t, req.Projects[i].Name, project.Name) - require.Equal(t, req.Projects[i].Source.Repository.Id, project.Repository.Id) - require.Equal(t, req.Projects[i].Source.Repository.Url, project.Repository.Url) - require.Equal(t, req.Projects[i].Source.Repository.Name, project.Repository.Name) - require.Equal(t, project.ApiKey, project.Name) - require.Equal(t, project.Target, req.Target) - require.Equal(t, project.Image, projectImage) - - if verbose { - require.Equal(t, workspace.Info.Projects[i].Name, workspaceInfo.Projects[i].Name) - require.Equal(t, workspace.Info.Projects[i].Created, workspaceInfo.Projects[i].Created) - require.Equal(t, workspace.Info.Projects[i].IsRunning, workspaceInfo.Projects[i].IsRunning) - require.Equal(t, workspace.Info.Projects[i].ProviderMetadata, workspaceInfo.Projects[i].ProviderMetadata) - } - } + + require.Equal(t, req.Name, workspace.Name) + require.Equal(t, req.Source.Repository.Id, workspace.Repository.Id) + require.Equal(t, req.Source.Repository.Url, workspace.Repository.Url) + require.Equal(t, req.Source.Repository.Name, workspace.Repository.Name) + require.Equal(t, workspace.ApiKey, workspace.Name) + require.Equal(t, workspace.Image, workspaceImage) } diff --git a/pkg/server/workspaces/start.go b/pkg/server/workspaces/start.go index a92fe3cf87..ddc4da4733 100644 --- a/pkg/server/workspaces/start.go +++ b/pkg/server/workspaces/start.go @@ -5,155 +5,44 @@ package workspaces import ( "context" - "fmt" - "io" - "github.com/daytonaio/daytona/pkg/containerregistry" - "github.com/daytonaio/daytona/pkg/gitprovider" - "github.com/daytonaio/daytona/pkg/logs" - "github.com/daytonaio/daytona/pkg/provider" - "github.com/daytonaio/daytona/pkg/provisioner" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/stores" "github.com/daytonaio/daytona/pkg/telemetry" - "github.com/daytonaio/daytona/pkg/workspace" - "github.com/daytonaio/daytona/pkg/workspace/project" log "github.com/sirupsen/logrus" - - "github.com/daytonaio/daytona/internal/util" ) -func (s *WorkspaceService) StartWorkspace(ctx context.Context, workspaceId string) error { - w, err := s.workspaceStore.Find(workspaceId) +func (s *WorkspaceService) Start(ctx context.Context, workspaceId string) error { + w, err := s.workspaceStore.Find(ctx, workspaceId) if err != nil { - return ErrWorkspaceNotFound + return s.handleStartError(ctx, w, stores.ErrWorkspaceNotFound) } - target, err := s.targetStore.Find(&provider.TargetFilter{Name: &w.Target}) + err = s.createJob(ctx, w.Id, w.Target.TargetConfig.ProviderInfo.RunnerId, models.JobActionStart) if err != nil { - return err + return s.handleStartError(ctx, w, err) } - workspaceLogger := s.loggerFactory.CreateWorkspaceLogger(w.Id, logs.LogSourceServer) - defer workspaceLogger.Close() - - wsLogWriter := io.MultiWriter(&util.InfoLogWriter{}, workspaceLogger) - - err = s.startWorkspace(ctx, w, target, wsLogWriter) + return s.handleStartError(ctx, w, err) +} +func (s *WorkspaceService) handleStartError(ctx context.Context, w *models.Workspace, err error) error { if !telemetry.TelemetryEnabled(ctx) { return err } clientId := telemetry.ClientId(ctx) - telemetryProps := telemetry.NewWorkspaceEventProps(ctx, w, target) - event := telemetry.ServerEventWorkspaceStarted + eventName := telemetry.WorkspaceEventLifecycleStarted if err != nil { - telemetryProps["error"] = err.Error() - event = telemetry.ServerEventWorkspaceStartError + eventName = telemetry.WorkspaceEventLifecycleStartFailed } - telemetryError := s.telemetryService.TrackServerEvent(event, clientId, telemetryProps) + event := telemetry.NewWorkspaceEvent(eventName, w, err, nil) + + telemetryError := s.trackTelemetryEvent(event, clientId) if telemetryError != nil { log.Trace(telemetryError) } return err } - -func (s *WorkspaceService) StartProject(ctx context.Context, workspaceId, projectName string) error { - w, err := s.workspaceStore.Find(workspaceId) - if err != nil { - return ErrWorkspaceNotFound - } - - project, err := w.GetProject(projectName) - if err != nil { - return ErrProjectNotFound - } - - target, err := s.targetStore.Find(&provider.TargetFilter{Name: &w.Target}) - if err != nil { - return err - } - - projectLogger := s.loggerFactory.CreateProjectLogger(w.Id, project.Name, logs.LogSourceServer) - defer projectLogger.Close() - - return s.startProject(ctx, project, target, projectLogger) -} - -func (s *WorkspaceService) startWorkspace(ctx context.Context, ws *workspace.Workspace, target *provider.ProviderTarget, wsLogWriter io.Writer) error { - wsLogWriter.Write([]byte("Starting workspace\n")) - - ws.EnvVars = workspace.GetWorkspaceEnvVars(ws, workspace.WorkspaceEnvVarParams{ - ApiUrl: s.serverApiUrl, - ServerUrl: s.serverUrl, - ServerVersion: s.serverVersion, - ClientId: telemetry.ClientId(ctx), - }, telemetry.TelemetryEnabled(ctx)) - - err := s.provisioner.StartWorkspace(ws, target) - if err != nil { - return err - } - - for _, project := range ws.Projects { - projectLogger := s.loggerFactory.CreateProjectLogger(ws.Id, project.Name, logs.LogSourceServer) - defer projectLogger.Close() - - err = s.startProject(ctx, project, target, projectLogger) - if err != nil { - return err - } - } - - wsLogWriter.Write([]byte(fmt.Sprintf("Workspace %s started\n", ws.Name))) - - return nil -} - -func (s *WorkspaceService) startProject(ctx context.Context, p *project.Project, target *provider.ProviderTarget, logWriter io.Writer) error { - logWriter.Write([]byte(fmt.Sprintf("Starting project %s\n", p.Name))) - - projectToStart := *p - projectToStart.EnvVars = project.GetProjectEnvVars(p, project.ProjectEnvVarParams{ - ApiUrl: s.serverApiUrl, - ServerUrl: s.serverUrl, - ServerVersion: s.serverVersion, - ClientId: telemetry.ClientId(ctx), - }, telemetry.TelemetryEnabled(ctx)) - - cr, err := s.containerRegistryService.FindByImageName(p.Image) - if err != nil && !containerregistry.IsContainerRegistryNotFound(err) { - return err - } - - builderCr, err := s.containerRegistryService.FindByImageName(s.builderImage) - if err != nil && !containerregistry.IsContainerRegistryNotFound(err) { - return err - } - - var gc *gitprovider.GitProviderConfig - - if p.GitProviderConfigId != nil { - gc, err = s.gitProviderService.GetConfig(*p.GitProviderConfigId) - if err != nil && !gitprovider.IsGitProviderNotFound(err) { - return err - } - } - - err = s.provisioner.StartProject(provisioner.ProjectParams{ - Project: &projectToStart, - Target: target, - ContainerRegistry: cr, - GitProviderConfig: gc, - BuilderImage: s.builderImage, - BuilderImageContainerRegistry: builderCr, - }) - if err != nil { - return err - } - - logWriter.Write([]byte(fmt.Sprintf("Project %s started\n", p.Name))) - - return nil -} diff --git a/pkg/server/workspaces/stop.go b/pkg/server/workspaces/stop.go index 83344bb5d7..dca0b6f969 100644 --- a/pkg/server/workspaces/stop.go +++ b/pkg/server/workspaces/stop.go @@ -5,86 +5,44 @@ package workspaces import ( "context" - "time" - "github.com/daytonaio/daytona/pkg/provider" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/stores" "github.com/daytonaio/daytona/pkg/telemetry" log "github.com/sirupsen/logrus" ) -func (s *WorkspaceService) StopWorkspace(ctx context.Context, workspaceId string) error { - workspace, err := s.workspaceStore.Find(workspaceId) +func (s *WorkspaceService) Stop(ctx context.Context, workspaceId string) error { + w, err := s.workspaceStore.Find(ctx, workspaceId) if err != nil { - return ErrWorkspaceNotFound + return s.handleStopError(ctx, w, stores.ErrWorkspaceNotFound) } - target, err := s.targetStore.Find(&provider.TargetFilter{Name: &workspace.Target}) + err = s.createJob(ctx, w.Id, w.Target.TargetConfig.ProviderInfo.RunnerId, models.JobActionStop) if err != nil { - return err - } - - for _, project := range workspace.Projects { - // todo: go routines - err := s.provisioner.StopProject(project, target) - if err != nil { - return err - } - if project.State != nil { - project.State.Uptime = 0 - project.State.UpdatedAt = time.Now().Format(time.RFC1123) - } + return s.handleStopError(ctx, w, err) } - err = s.provisioner.StopWorkspace(workspace, target) - if err == nil { - err = s.workspaceStore.Save(workspace) - } + return s.handleStopError(ctx, w, err) +} +func (s *WorkspaceService) handleStopError(ctx context.Context, w *models.Workspace, err error) error { if !telemetry.TelemetryEnabled(ctx) { return err } clientId := telemetry.ClientId(ctx) - telemetryProps := telemetry.NewWorkspaceEventProps(ctx, workspace, target) - event := telemetry.ServerEventWorkspaceStopped + eventName := telemetry.WorkspaceEventLifecycleStopped if err != nil { - telemetryProps["error"] = err.Error() - event = telemetry.ServerEventWorkspaceStopError + eventName = telemetry.WorkspaceEventLifecycleStopFailed } - telemetryError := s.telemetryService.TrackServerEvent(event, clientId, telemetryProps) + event := telemetry.NewWorkspaceEvent(eventName, w, err, nil) + + telemetryError := s.trackTelemetryEvent(event, clientId) if telemetryError != nil { log.Trace(telemetryError) } return err } - -func (s *WorkspaceService) StopProject(ctx context.Context, workspaceId, projectName string) error { - w, err := s.workspaceStore.Find(workspaceId) - if err != nil { - return ErrWorkspaceNotFound - } - - project, err := w.GetProject(projectName) - if err != nil { - return ErrProjectNotFound - } - - target, err := s.targetStore.Find(&provider.TargetFilter{Name: &w.Target}) - if err != nil { - return err - } - - err = s.provisioner.StopProject(project, target) - if err != nil { - return err - } - - if project.State != nil { - project.State.Uptime = 0 - project.State.UpdatedAt = time.Now().Format(time.RFC1123) - } - - return s.workspaceStore.Save(w) -} diff --git a/pkg/server/workspacetemplates/prebuild.go b/pkg/server/workspacetemplates/prebuild.go new file mode 100644 index 0000000000..bcbc9c0e12 --- /dev/null +++ b/pkg/server/workspacetemplates/prebuild.go @@ -0,0 +1,213 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package workspacetemplates + +import ( + "context" + "fmt" + "sort" + + "github.com/daytonaio/daytona/pkg/gitprovider" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/scheduler" + "github.com/daytonaio/daytona/pkg/services" + "github.com/daytonaio/daytona/pkg/stores" + log "github.com/sirupsen/logrus" +) + +// TODO: add lock when running interval func +// 1 second interval +const DEFAULT_RETENTION_POLL_INTERVAL = "*/1 * * * * *" + +func (s *WorkspaceTemplateService) FindPrebuild(ctx context.Context, workspaceTemplateFilter *stores.WorkspaceTemplateFilter, prebuildFilter *stores.PrebuildFilter) (*services.PrebuildDTO, error) { + wt, err := s.templateStore.Find(ctx, workspaceTemplateFilter) + if err != nil { + return nil, stores.ErrWorkspaceTemplateNotFound + } + + prebuild, err := wt.FindPrebuild(&models.MatchParams{ + Id: prebuildFilter.Id, + Branch: prebuildFilter.Branch, + CommitInterval: prebuildFilter.CommitInterval, + TriggerFiles: prebuildFilter.TriggerFiles, + WorkspaceTemplateName: prebuildFilter.WorkspaceTemplateName, + }) + if err != nil { + return nil, err + } + + return &services.PrebuildDTO{ + Id: prebuild.Id, + WorkspaceTemplateName: wt.Name, + Branch: prebuild.Branch, + CommitInterval: prebuild.CommitInterval, + TriggerFiles: prebuild.TriggerFiles, + Retention: prebuild.Retention, + }, nil +} + +func (s *WorkspaceTemplateService) ListPrebuilds(ctx context.Context, workspaceTemplateFilter *stores.WorkspaceTemplateFilter, prebuildFilter *stores.PrebuildFilter) ([]*services.PrebuildDTO, error) { + var result []*services.PrebuildDTO + wts, err := s.templateStore.List(ctx, workspaceTemplateFilter) + if err != nil { + return nil, stores.ErrWorkspaceTemplateNotFound + } + + for _, wt := range wts { + for _, prebuild := range wt.Prebuilds { + result = append(result, &services.PrebuildDTO{ + Id: prebuild.Id, + WorkspaceTemplateName: wt.Name, + Branch: prebuild.Branch, + CommitInterval: prebuild.CommitInterval, + TriggerFiles: prebuild.TriggerFiles, + Retention: prebuild.Retention, + }) + } + } + + return result, nil +} + +// TODO: revise build trigger strategy +// We should discuss if the function should throw if the build can not be created or move on to the next one +func (s *WorkspaceTemplateService) ProcessGitEvent(ctx context.Context, data gitprovider.GitEventData) error { + workspaceTemplates, err := s.List(ctx, &stores.WorkspaceTemplateFilter{ + Url: &data.Url, + }) + if err != nil { + return err + } + + repo, _, err := s.getRepositoryContext(ctx, data.Url) + if err != nil { + return fmt.Errorf("failed to get repository context: %s", err) + } + + for _, workspaceTemplate := range workspaceTemplates { + prebuild, err := workspaceTemplate.FindPrebuild(&models.MatchParams{ + Branch: &data.Branch, + }) + if err != nil || prebuild == nil { + continue + } + + // Check if the commit's affected files and prebuild config's trigger files have any overlap + if len(prebuild.TriggerFiles) > 0 { + if slicesHaveCommonEntry(prebuild.TriggerFiles, data.AffectedFiles) { + err := s.createBuild(ctx, workspaceTemplate, repo, prebuild.Id) + if err != nil { + return fmt.Errorf("failed to create build: %s", err) + } + continue + } + } + + newestBuild, err := s.findNewestBuild(ctx, prebuild.Id) + if err != nil { + err := s.createBuild(ctx, workspaceTemplate, repo, prebuild.Id) + if err != nil { + return fmt.Errorf("failed to create build: %s", err) + } + continue + } + + commitsRange, err := s.getCommitsRange(ctx, repo, newestBuild.Repository.Sha, data.Sha) + if err != nil { + return fmt.Errorf("failed to get commits range: %s", err) + } + + // Check if the commit interval has been reached + if prebuild.CommitInterval != nil && commitsRange >= *prebuild.CommitInterval { + err := s.createBuild(ctx, workspaceTemplate, repo, prebuild.Id) + if err != nil { + return fmt.Errorf("failed to create build: %s", err) + } + } + } + + return nil +} + +// Marks the [retention] oldest published builds for deletion for each prebuild +func (s *WorkspaceTemplateService) EnforceRetentionPolicy(ctx context.Context) error { + prebuilds, err := s.ListPrebuilds(ctx, nil, nil) + if err != nil { + return err + } + + existingBuilds, err := s.listSuccessfulBuilds(ctx) + if err != nil { + return err + } + + buildMap := make(map[string][]models.Build) + + // Group builds by their prebuildId + for _, b := range existingBuilds { + if b.PrebuildId != nil && *b.PrebuildId != "" { + buildMap[*b.PrebuildId] = append(buildMap[*b.PrebuildId], b.Build) + } + } + + for _, prebuild := range prebuilds { + + associatedBuilds := buildMap[prebuild.Id] + + if len(associatedBuilds) > prebuild.Retention { + // Sort the builds by creation time in ascending order (oldest first) + sort.Slice(associatedBuilds, func(i, j int) bool { + return associatedBuilds[i].CreatedAt.Before(associatedBuilds[j].CreatedAt) + }) + + numToDelete := len(associatedBuilds) - prebuild.Retention + + // Mark the oldest builds for deletion + for i := 0; i < numToDelete; i++ { + errs := s.deleteBuilds(ctx, &associatedBuilds[i].Id, nil, false) + if len(errs) > 0 { + for _, err := range errs { + log.Error(err) + } + } + } + } + + } + + return nil +} + +func (s *WorkspaceTemplateService) StartRetentionPoller(ctx context.Context) error { + scheduler := scheduler.NewCronScheduler() + + err := scheduler.AddFunc(DEFAULT_RETENTION_POLL_INTERVAL, func() { + err := s.EnforceRetentionPolicy(ctx) + if err != nil { + log.Error(err) + } + }) + if err != nil { + return err + } + + scheduler.Start() + return nil +} + +func slicesHaveCommonEntry(slice1, slice2 []string) bool { + entryMap := make(map[string]bool) + + for _, entry := range slice1 { + entryMap[entry] = true + } + + for _, entry := range slice2 { + if entryMap[entry] { + return true + } + } + + return false +} diff --git a/pkg/server/workspacetemplates/prebuild_delete.go b/pkg/server/workspacetemplates/prebuild_delete.go new file mode 100644 index 0000000000..7ffb9ca081 --- /dev/null +++ b/pkg/server/workspacetemplates/prebuild_delete.go @@ -0,0 +1,104 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package workspacetemplates + +import ( + "context" + + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/stores" + "github.com/daytonaio/daytona/pkg/telemetry" + + log "github.com/sirupsen/logrus" +) + +func (s *WorkspaceTemplateService) DeletePrebuild(ctx context.Context, workspaceTemplateName string, id string, force bool) []error { + workspaceTemplate, err := s.Find(ctx, &stores.WorkspaceTemplateFilter{ + Name: &workspaceTemplateName, + }) + if err != nil { + return []error{s.handleDeletePrebuildError(ctx, nil, err)} + } + + // Get all prebuilds for this workspace template's repository URL and + // if this is the last prebuild, unregister the Git provider webhook + prebuilds, err := s.ListPrebuilds(ctx, &stores.WorkspaceTemplateFilter{ + Url: &workspaceTemplate.RepositoryUrl, + }, nil) + if err != nil { + return []error{s.handleDeletePrebuildError(ctx, workspaceTemplate, err)} + } + + if len(prebuilds) == 1 { + repository, gitProviderId, err := s.getRepositoryContext(ctx, workspaceTemplate.RepositoryUrl) + if err != nil { + return []error{s.handleDeletePrebuildError(ctx, workspaceTemplate, err)} + } + + existingWebhookId, err := s.findPrebuildWebhook(ctx, gitProviderId, repository, s.prebuildWebhookEndpoint) + if err != nil { + if force { + log.Error(s.handleDeletePrebuildError(ctx, workspaceTemplate, err)) + } else { + return []error{s.handleDeletePrebuildError(ctx, workspaceTemplate, err)} + } + } + + if existingWebhookId != nil { + err = s.unregisterPrebuildWebhook(ctx, gitProviderId, repository, *existingWebhookId) + if err != nil { + if force { + log.Error(s.handleDeletePrebuildError(ctx, workspaceTemplate, err)) + } else { + return []error{s.handleDeletePrebuildError(ctx, workspaceTemplate, err)} + } + } + } + } + + errs := s.deleteBuilds(ctx, nil, &id, force) + if len(errs) > 0 { + for _, err := range errs { + err = s.handleDeletePrebuildError(ctx, workspaceTemplate, err) + if force { + log.Error(err) + } + } + if !force { + return errs + } + } + + err = workspaceTemplate.DeletePrebuild(id) + if err != nil { + return []error{s.handleDeletePrebuildError(ctx, workspaceTemplate, err)} + } + + err = s.templateStore.Save(ctx, workspaceTemplate) + err = s.handleDeletePrebuildError(ctx, workspaceTemplate, err) + if err != nil { + return []error{err} + } + + return nil +} + +func (s *WorkspaceTemplateService) handleDeletePrebuildError(ctx context.Context, workspaceTemplate *models.WorkspaceTemplate, err error) error { + if !telemetry.TelemetryEnabled(ctx) { + return err + } + + eventName := telemetry.WorkspaceTemplateEventPrebuildDeleted + if err != nil { + eventName = telemetry.WorkspaceTemplateEventPrebuildDeletionFailed + } + + event := telemetry.NewWorkspaceTemplateEvent(eventName, workspaceTemplate, err, nil) + telemetryError := s.trackTelemetryEvent(event, telemetry.ClientId(ctx)) + if telemetryError != nil { + log.Trace(telemetryError) + } + + return err +} diff --git a/pkg/server/workspacetemplates/prebuild_save.go b/pkg/server/workspacetemplates/prebuild_save.go new file mode 100644 index 0000000000..ddd4b2040d --- /dev/null +++ b/pkg/server/workspacetemplates/prebuild_save.go @@ -0,0 +1,119 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package workspacetemplates + +import ( + "context" + "errors" + + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/services" + "github.com/daytonaio/daytona/pkg/stores" + "github.com/daytonaio/daytona/pkg/telemetry" + log "github.com/sirupsen/logrus" +) + +func (s *WorkspaceTemplateService) SavePrebuild(ctx context.Context, workspaceTemplateName string, createPrebuildDto services.CreatePrebuildDTO) (*services.PrebuildDTO, error) { + workspaceTemplate, err := s.Find(ctx, &stores.WorkspaceTemplateFilter{ + Name: &workspaceTemplateName, + }) + if err != nil { + return nil, s.handleSavePrebuildError(ctx, nil, err) + } + + existingPrebuild, _ := workspaceTemplate.FindPrebuild(&models.MatchParams{ + Branch: &createPrebuildDto.Branch, + }) + + if existingPrebuild != nil && createPrebuildDto.Id == nil { + return nil, s.handleSavePrebuildError(ctx, workspaceTemplate, errors.New("prebuild for the specified workspace template and branch already exists")) + } + + if createPrebuildDto.CommitInterval == nil && len(createPrebuildDto.TriggerFiles) == 0 { + return nil, s.handleSavePrebuildError(ctx, workspaceTemplate, errors.New("either the commit interval or trigger files must be specified")) + } + + repository, gitProviderId, err := s.getRepositoryContext(ctx, workspaceTemplate.RepositoryUrl) + if err != nil { + return nil, s.handleSavePrebuildError(ctx, workspaceTemplate, err) + } + + prebuild := &models.PrebuildConfig{ + Branch: createPrebuildDto.Branch, + CommitInterval: createPrebuildDto.CommitInterval, + TriggerFiles: createPrebuildDto.TriggerFiles, + Retention: createPrebuildDto.Retention, + } + + if createPrebuildDto.Id != nil { + prebuild.Id = *createPrebuildDto.Id + } else { + err = prebuild.GenerateId() + if err != nil { + return nil, s.handleSavePrebuildError(ctx, workspaceTemplate, err) + } + } + + err = workspaceTemplate.SetPrebuild(prebuild) + if err != nil { + return nil, s.handleSavePrebuildError(ctx, workspaceTemplate, err) + } + + // Remember the new webhook ID in case config saving fails + newWebhookId := "" + + existingWebhookId, err := s.findPrebuildWebhook(ctx, gitProviderId, repository, s.prebuildWebhookEndpoint) + if err != nil { + return nil, s.handleSavePrebuildError(ctx, workspaceTemplate, err) + } + + if existingWebhookId == nil { + newWebhookId, err = s.registerPrebuildWebhook(ctx, gitProviderId, repository, s.prebuildWebhookEndpoint) + if err != nil { + return nil, s.handleSavePrebuildError(ctx, workspaceTemplate, err) + } + } + + err = s.templateStore.Save(ctx, workspaceTemplate) + if err != nil { + if newWebhookId != "" { + err = s.unregisterPrebuildWebhook(ctx, gitProviderId, repository, newWebhookId) + if err != nil { + log.Error(err) + } + } + + return nil, s.handleSavePrebuildError(ctx, workspaceTemplate, err) + } + + return &services.PrebuildDTO{ + Id: prebuild.Id, + WorkspaceTemplateName: workspaceTemplate.Name, + Branch: prebuild.Branch, + CommitInterval: prebuild.CommitInterval, + TriggerFiles: prebuild.TriggerFiles, + Retention: prebuild.Retention, + }, s.handleSavePrebuildError(ctx, workspaceTemplate, err) +} + +func (s *WorkspaceTemplateService) handleSavePrebuildError(ctx context.Context, workspaceTemplate *models.WorkspaceTemplate, err error) error { + if !telemetry.TelemetryEnabled(ctx) { + return err + } + + clientId := telemetry.ClientId(ctx) + + eventName := telemetry.WorkspaceTemplateEventPrebuildSaved + if err != nil { + eventName = telemetry.WorkspaceTemplateEventPrebuildSaveFailed + } + event := telemetry.NewWorkspaceTemplateEvent(eventName, workspaceTemplate, err, nil) + + telemetryError := s.trackTelemetryEvent(event, clientId) + if telemetryError != nil { + log.Trace(telemetryError) + } + + return err +} diff --git a/pkg/server/workspacetemplates/prebuild_test.go b/pkg/server/workspacetemplates/prebuild_test.go new file mode 100644 index 0000000000..875cad39f2 --- /dev/null +++ b/pkg/server/workspacetemplates/prebuild_test.go @@ -0,0 +1,247 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package workspacetemplates_test + +import ( + "context" + "time" + + "github.com/daytonaio/daytona/internal/util" + "github.com/daytonaio/daytona/pkg/gitprovider" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/services" + "github.com/daytonaio/daytona/pkg/stores" +) + +var prebuild1 = &models.PrebuildConfig{ + Id: "1", + Branch: "feat", + CommitInterval: util.Pointer(3), + Retention: 3, + TriggerFiles: []string{"file1", "file2"}, +} + +var prebuild2 = &models.PrebuildConfig{ + Id: "2", + Branch: "dev", + CommitInterval: util.Pointer(1), + Retention: 3, + TriggerFiles: []string{"file1", "file2"}, +} + +var prebuild3 = &models.PrebuildConfig{ + Id: "3", + Branch: "new", + CommitInterval: util.Pointer(1), + Retention: 3, + TriggerFiles: []string{"file1", "file2"}, +} + +var prebuild1Dto = &services.PrebuildDTO{ + WorkspaceTemplateName: workspaceTemplate1.Name, + Id: prebuild1.Id, + Branch: prebuild1.Branch, + CommitInterval: prebuild1.CommitInterval, + Retention: prebuild1.Retention, + TriggerFiles: prebuild1.TriggerFiles, +} + +var repository1 *gitprovider.GitRepository = &gitprovider.GitRepository{ + Url: "https://github.com/daytonaio/daytona.git", + Branch: "main", + Sha: "sha1", +} + +var expectedPrebuilds []*models.PrebuildConfig +var expectedFilteredPrebuilds []*models.PrebuildConfig + +var expectedPrebuildsMap map[string]*models.PrebuildConfig +var expectedFilteredPrebuildsMap map[string]*models.PrebuildConfig + +func (s *WorkspaceTemplateServiceTestSuite) TestSetPrebuild() { + require := s.Require() + + s.gitProviderService.On("GetGitProviderForUrl", repository1.Url).Return(&s.gitProvider, "github", nil) + s.gitProvider.On("GetRepositoryContext", gitprovider.GetRepositoryContext{ + Url: repository1.Url, + }).Return(repository1, nil) + s.gitProviderService.On("GetPrebuildWebhook", "github", repository1, "").Return(util.Pointer("webhook-id"), nil) + + newPrebuildDto, err := s.workspaceTemplateService.SavePrebuild(context.TODO(), workspaceTemplate1.Name, services.CreatePrebuildDTO{ + Id: &prebuild3.Id, + Branch: prebuild3.Branch, + CommitInterval: prebuild3.CommitInterval, + Retention: prebuild3.Retention, + TriggerFiles: prebuild3.TriggerFiles, + }) + require.Nil(err) + + prebuildDtos, err := s.workspaceTemplateService.ListPrebuilds(context.TODO(), &stores.WorkspaceTemplateFilter{ + Name: &workspaceTemplate1.Name, + }, nil) + require.Nil(err) + require.Contains(prebuildDtos, newPrebuildDto) +} + +func (s *WorkspaceTemplateServiceTestSuite) TestFindPrebuild() { + require := s.Require() + + prebuild, err := s.workspaceTemplateService.FindPrebuild(context.TODO(), &stores.WorkspaceTemplateFilter{ + Name: &workspaceTemplate1.Name, + }, &stores.PrebuildFilter{ + Id: &prebuild1.Id, + }) + require.Nil(err) + require.Equal(prebuild1Dto, prebuild) +} +func (s *WorkspaceTemplateServiceTestSuite) TestListPrebuilds() { + require := s.Require() + + prebuildDtos, err := s.workspaceTemplateService.ListPrebuilds(context.TODO(), &stores.WorkspaceTemplateFilter{ + Name: &workspaceTemplate1.Name, + }, nil) + require.Nil(err) + + require.Contains(prebuildDtos, prebuild1Dto) +} + +func (s *WorkspaceTemplateServiceTestSuite) TestDeletePrebuild() { + expectedPrebuilds = expectedPrebuilds[:1] + + require := s.Require() + + s.buildService.On("Delete", &services.BuildFilter{ + StoreFilter: stores.BuildFilter{ + PrebuildIds: &[]string{prebuild2.Id}, + }, + }, false).Return([]error{}) + + err := s.workspaceTemplateService.DeletePrebuild(context.TODO(), workspaceTemplate1.Name, prebuild2.Id, false) + require.Nil(err) + + prebuildDtos, errs := s.workspaceTemplateService.ListPrebuilds(context.TODO(), &stores.WorkspaceTemplateFilter{ + Name: &workspaceTemplate1.Name, + }, nil) + require.Nil(errs) + require.ElementsMatch([]*services.PrebuildDTO{ + prebuild1Dto, + }, prebuildDtos) +} + +func (s *WorkspaceTemplateServiceTestSuite) TestProcessGitEventCommitInterval() { + require := s.Require() + + s.gitProviderService.On("GetGitProviderForUrl", repository1.Url).Return(&s.gitProvider, "github", nil) + s.gitProvider.On("GetRepositoryContext", gitprovider.GetRepositoryContext{ + Url: repository1.Url, + }).Return(repository1, nil) + + s.buildService.On("Create", services.CreateBuildDTO{ + PrebuildId: &prebuild1.Id, + Branch: repository1.Branch, + WorkspaceTemplateName: workspaceTemplate1.Name, + EnvVars: workspaceTemplate1.EnvVars, + }).Return("", nil) + + s.buildService.On("Find", &services.BuildFilter{ + StoreFilter: stores.BuildFilter{ + PrebuildIds: &[]string{prebuild1.Id}, + GetNewest: util.Pointer(true), + }, + }).Return(&services.BuildDTO{ + Build: models.Build{ + Id: "1", + PrebuildId: &prebuild1.Id, + Repository: repository1, + }, + }, nil) + + data := gitprovider.GitEventData{ + Url: repository1.Url, + Branch: "feat", + Sha: "sha4", + Owner: repository1.Owner, + AffectedFiles: []string{}, + } + + s.gitProvider.On("GetCommitsRange", repository1, repository1.Sha, data.Sha).Return(3, nil) + + err := s.workspaceTemplateService.ProcessGitEvent(context.TODO(), data) + require.Nil(err) +} + +func (s *WorkspaceTemplateServiceTestSuite) TestProcessGitEventTriggerFiles() { + require := s.Require() + + s.gitProviderService.On("GetGitProviderForUrl", repository1.Url).Return(&s.gitProvider, "github", nil) + s.gitProvider.On("GetRepositoryContext", gitprovider.GetRepositoryContext{ + Url: repository1.Url, + }).Return(repository1, nil) + + s.buildService.On("Create", services.CreateBuildDTO{ + PrebuildId: &prebuild1.Id, + Branch: repository1.Branch, + WorkspaceTemplateName: workspaceTemplate1.Name, + EnvVars: workspaceTemplate1.EnvVars, + }).Return("", nil) + + data := gitprovider.GitEventData{ + Url: repository1.Url, + Branch: "feat", + Sha: "sha4", + Owner: repository1.Owner, + AffectedFiles: []string{ + "file1", + }, + } + + err := s.workspaceTemplateService.ProcessGitEvent(context.TODO(), data) + require.Nil(err) +} + +func (s *WorkspaceTemplateServiceTestSuite) TestEnforceRetentionPolicy() { + require := s.Require() + + s.buildService.On("List", &services.BuildFilter{ + StateNames: &[]models.ResourceStateName{models.ResourceStateNameRunSuccessful}, + }).Return([]*services.BuildDTO{ + { + Build: models.Build{ + Id: "1", + PrebuildId: util.Pointer("1"), + CreatedAt: time.Now().Add(time.Hour * -4), + }, + }, + { + Build: models.Build{ + Id: "2", + PrebuildId: util.Pointer("1"), + CreatedAt: time.Now().Add(time.Hour * -3), + }, + }, + { + Build: models.Build{ + Id: "3", + PrebuildId: util.Pointer("1"), + CreatedAt: time.Now().Add(time.Hour * -2), + }, + }, + { + Build: models.Build{ + Id: "4", + PrebuildId: util.Pointer("1"), + CreatedAt: time.Now().Add(time.Hour * -1), + }, + }, + }, nil) + + s.buildService.On("Delete", &services.BuildFilter{ + StoreFilter: stores.BuildFilter{ + Id: util.Pointer("1"), + }, + }, false).Return([]error{}) + + err := s.workspaceTemplateService.EnforceRetentionPolicy(context.TODO()) + require.Nil(err) +} diff --git a/pkg/server/workspacetemplates/service.go b/pkg/server/workspacetemplates/service.go new file mode 100644 index 0000000000..895d357892 --- /dev/null +++ b/pkg/server/workspacetemplates/service.go @@ -0,0 +1,196 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package workspacetemplates + +import ( + "context" + "strings" + + "github.com/daytonaio/daytona/internal/util" + "github.com/daytonaio/daytona/pkg/gitprovider" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/services" + "github.com/daytonaio/daytona/pkg/stores" + "github.com/daytonaio/daytona/pkg/telemetry" + + log "github.com/sirupsen/logrus" +) + +type WorkspaceTemplateServiceConfig struct { + PrebuildWebhookEndpoint string + ConfigStore stores.WorkspaceTemplateStore + + FindNewestBuild func(ctx context.Context, prebuildId string) (*services.BuildDTO, error) + ListSuccessfulBuilds func(ctx context.Context) ([]*services.BuildDTO, error) + CreateBuild func(ctx context.Context, wt *models.WorkspaceTemplate, repo *gitprovider.GitRepository, prebuildId string) error + DeleteBuilds func(ctx context.Context, id, prebuildId *string, force bool) []error + GetRepositoryContext func(ctx context.Context, url string) (repo *gitprovider.GitRepository, gitProviderId string, err error) + FindPrebuildWebhook func(ctx context.Context, gitProviderId string, repo *gitprovider.GitRepository, endpointUrl string) (*string, error) + UnregisterPrebuildWebhook func(ctx context.Context, gitProviderId string, repo *gitprovider.GitRepository, id string) error + RegisterPrebuildWebhook func(ctx context.Context, gitProviderId string, repo *gitprovider.GitRepository, endpointUrl string) (string, error) + GetCommitsRange func(ctx context.Context, repo *gitprovider.GitRepository, initialSha string, currentSha string) (int, error) + TrackTelemetryEvent func(event telemetry.Event, clientId string) error +} + +type WorkspaceTemplateService struct { + prebuildWebhookEndpoint string + templateStore stores.WorkspaceTemplateStore + + findNewestBuild func(ctx context.Context, prebuildId string) (*services.BuildDTO, error) + listSuccessfulBuilds func(ctx context.Context) ([]*services.BuildDTO, error) + createBuild func(ctx context.Context, wt *models.WorkspaceTemplate, repo *gitprovider.GitRepository, prebuildId string) error + deleteBuilds func(ctx context.Context, id, prebuildId *string, force bool) []error + getRepositoryContext func(ctx context.Context, url string) (repo *gitprovider.GitRepository, gitProviderId string, err error) + getCommitsRange func(ctx context.Context, repo *gitprovider.GitRepository, initialSha string, currentSha string) (int, error) + findPrebuildWebhook func(ctx context.Context, gitProviderId string, repo *gitprovider.GitRepository, endpointUrl string) (*string, error) + unregisterPrebuildWebhook func(ctx context.Context, gitProviderId string, repo *gitprovider.GitRepository, id string) error + registerPrebuildWebhook func(ctx context.Context, gitProviderId string, repo *gitprovider.GitRepository, endpointUrl string) (string, error) + trackTelemetryEvent func(event telemetry.Event, clientId string) error +} + +func NewWorkspaceTemplateService(config WorkspaceTemplateServiceConfig) services.IWorkspaceTemplateService { + return &WorkspaceTemplateService{ + prebuildWebhookEndpoint: config.PrebuildWebhookEndpoint, + templateStore: config.ConfigStore, + findNewestBuild: config.FindNewestBuild, + listSuccessfulBuilds: config.ListSuccessfulBuilds, + createBuild: config.CreateBuild, + deleteBuilds: config.DeleteBuilds, + getRepositoryContext: config.GetRepositoryContext, + findPrebuildWebhook: config.FindPrebuildWebhook, + unregisterPrebuildWebhook: config.UnregisterPrebuildWebhook, + registerPrebuildWebhook: config.RegisterPrebuildWebhook, + getCommitsRange: config.GetCommitsRange, + trackTelemetryEvent: config.TrackTelemetryEvent, + } +} + +func (s *WorkspaceTemplateService) List(ctx context.Context, filter *stores.WorkspaceTemplateFilter) ([]*models.WorkspaceTemplate, error) { + return s.templateStore.List(ctx, filter) +} + +func (s *WorkspaceTemplateService) SetDefault(ctx context.Context, workspaceTemplateName string) error { + var err error + ctx, err = s.templateStore.BeginTransaction(ctx) + if err != nil { + return err + } + + defer stores.RecoverAndRollback(ctx, s.templateStore) + + workspaceTemplate, err := s.Find(ctx, &stores.WorkspaceTemplateFilter{ + Name: &workspaceTemplateName, + }) + if err != nil { + return s.templateStore.RollbackTransaction(ctx, err) + } + + defaultWorkspaceTemplate, err := s.Find(ctx, &stores.WorkspaceTemplateFilter{ + Url: &workspaceTemplate.RepositoryUrl, + Default: util.Pointer(true), + }) + if err != nil && !stores.IsWorkspaceTemplateNotFound(err) { + return s.templateStore.RollbackTransaction(ctx, err) + } + + if defaultWorkspaceTemplate != nil { + defaultWorkspaceTemplate.IsDefault = false + err := s.templateStore.Save(ctx, defaultWorkspaceTemplate) + if err != nil { + return s.templateStore.RollbackTransaction(ctx, err) + } + } + + workspaceTemplate.IsDefault = true + err = s.templateStore.Save(ctx, workspaceTemplate) + if err != nil { + return s.templateStore.RollbackTransaction(ctx, err) + } + + return s.templateStore.CommitTransaction(ctx) +} + +func (s *WorkspaceTemplateService) Find(ctx context.Context, filter *stores.WorkspaceTemplateFilter) (*models.WorkspaceTemplate, error) { + if filter != nil && filter.Url != nil { + cleanedUrl := util.CleanUpRepositoryUrl(*filter.Url) + if !strings.HasSuffix(cleanedUrl, ".git") { + cleanedUrl = cleanedUrl + ".git" + } + filter.Url = util.Pointer(cleanedUrl) + } + return s.templateStore.Find(ctx, filter) +} + +func (s *WorkspaceTemplateService) Save(ctx context.Context, workspaceTemplate *models.WorkspaceTemplate) error { + workspaceTemplate.RepositoryUrl = util.CleanUpRepositoryUrl(workspaceTemplate.RepositoryUrl) + + clientId := telemetry.ClientId(ctx) + + eventName := telemetry.WorkspaceTemplateEventLifecycleSaved + + err := s.templateStore.Save(ctx, workspaceTemplate) + if err != nil { + eventName = telemetry.WorkspaceTemplateEventLifecycleSaveFailed + } + + if telemetry.TelemetryEnabled(ctx) { + event := telemetry.NewWorkspaceTemplateEvent(eventName, workspaceTemplate, err, nil) + telemetryError := s.trackTelemetryEvent(event, clientId) + if telemetryError != nil { + log.Trace(telemetryError) + } + } + + if err != nil { + return err + } + + return s.SetDefault(ctx, workspaceTemplate.Name) +} + +func (s *WorkspaceTemplateService) Delete(ctx context.Context, workspaceTemplateName string, force bool) []error { + wt, err := s.Find(ctx, &stores.WorkspaceTemplateFilter{ + Name: &workspaceTemplateName, + }) + if err != nil { + return []error{s.handleDeleteError(ctx, nil, err)} + } + + // DeletePrebuild handles deleting the builds and removing the webhook + for _, prebuild := range wt.Prebuilds { + errs := s.DeletePrebuild(ctx, wt.Name, prebuild.Id, force) + if len(errs) > 0 { + return errs + } + } + + err = s.templateStore.Delete(ctx, wt) + err = s.handleDeleteError(ctx, wt, err) + if err != nil { + return []error{err} + } + + return nil +} + +func (s *WorkspaceTemplateService) handleDeleteError(ctx context.Context, wt *models.WorkspaceTemplate, err error) error { + if !telemetry.TelemetryEnabled(ctx) { + return err + } + + clientId := telemetry.ClientId(ctx) + + eventName := telemetry.WorkspaceTemplateEventLifecycleDeleted + if err != nil { + eventName = telemetry.WorkspaceTemplateEventLifecycleDeletionFailed + } + event := telemetry.NewWorkspaceTemplateEvent(eventName, wt, err, nil) + + telemetryError := s.trackTelemetryEvent(event, clientId) + if telemetryError != nil { + log.Trace(telemetryError) + } + + return err +} diff --git a/pkg/server/workspacetemplates/service_test.go b/pkg/server/workspacetemplates/service_test.go new file mode 100644 index 0000000000..2c324ab64f --- /dev/null +++ b/pkg/server/workspacetemplates/service_test.go @@ -0,0 +1,263 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package workspacetemplates_test + +import ( + "context" + "testing" + + git_provider_mock "github.com/daytonaio/daytona/internal/testing/gitprovider/mocks" + "github.com/daytonaio/daytona/internal/testing/server/targets/mocks" + workspacetemplate_internal "github.com/daytonaio/daytona/internal/testing/server/workspacetemplate" + "github.com/daytonaio/daytona/internal/util" + "github.com/daytonaio/daytona/pkg/gitprovider" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/server/workspacetemplates" + "github.com/daytonaio/daytona/pkg/services" + "github.com/daytonaio/daytona/pkg/stores" + "github.com/stretchr/testify/suite" +) + +var workspaceTemplate1Image = "image1" +var workspaceTemplate1User = "user1" + +var workspaceTemplate1 = &models.WorkspaceTemplate{ + Name: "wt1", + Image: workspaceTemplate1Image, + User: workspaceTemplate1User, + BuildConfig: nil, + RepositoryUrl: repository1.Url, + IsDefault: true, + Prebuilds: []*models.PrebuildConfig{ + prebuild1, + prebuild2, + }, +} + +var workspaceTemplate2 = &models.WorkspaceTemplate{ + Name: "wt2", + Image: "image2", + User: "user2", + BuildConfig: nil, + RepositoryUrl: "https://github.com/daytonaio/daytona.git", +} + +var workspaceTemplate3 = &models.WorkspaceTemplate{ + Name: "wt3", + Image: "image3", + User: "user3", + BuildConfig: nil, + RepositoryUrl: "https://github.com/daytonaio/daytona3.git", +} + +var workspaceTemplate4 = &models.WorkspaceTemplate{ + Name: "wt4", + Image: "image4", + User: "user4", + BuildConfig: nil, + RepositoryUrl: "https://github.com/daytonaio/daytona4.git", +} + +var expectedWorkspaceTemplates []*models.WorkspaceTemplate +var expectedFilteredWorkspaceTemplates []*models.WorkspaceTemplate + +var expectedWorkspaceTemplatesMap map[string]*models.WorkspaceTemplate +var expectedFilteredWorkspaceTemplatesMap map[string]*models.WorkspaceTemplate + +type WorkspaceTemplateServiceTestSuite struct { + suite.Suite + workspaceTemplateService services.IWorkspaceTemplateService + workspaceTemplateStore stores.WorkspaceTemplateStore + gitProviderService mocks.MockGitProviderService + buildService mocks.MockBuildService + gitProvider git_provider_mock.MockGitProvider +} + +func NewConfigServiceTestSuite() *WorkspaceTemplateServiceTestSuite { + return &WorkspaceTemplateServiceTestSuite{} +} + +func (s *WorkspaceTemplateServiceTestSuite) SetupTest() { + expectedWorkspaceTemplates = []*models.WorkspaceTemplate{ + workspaceTemplate1, workspaceTemplate2, workspaceTemplate3, + } + + expectedPrebuilds = []*models.PrebuildConfig{ + prebuild1, prebuild2, + } + + expectedWorkspaceTemplatesMap = map[string]*models.WorkspaceTemplate{ + workspaceTemplate1.Name: workspaceTemplate1, + workspaceTemplate2.Name: workspaceTemplate2, + workspaceTemplate3.Name: workspaceTemplate3, + } + + expectedPrebuildsMap = map[string]*models.PrebuildConfig{ + prebuild1.Id: prebuild1, + prebuild2.Id: prebuild2, + } + + expectedFilteredWorkspaceTemplates = []*models.WorkspaceTemplate{ + workspaceTemplate1, workspaceTemplate2, + } + + expectedFilteredPrebuilds = []*models.PrebuildConfig{ + prebuild1, + } + + expectedFilteredWorkspaceTemplatesMap = map[string]*models.WorkspaceTemplate{ + workspaceTemplate1.Name: workspaceTemplate1, + workspaceTemplate2.Name: workspaceTemplate2, + } + + expectedFilteredPrebuildsMap = map[string]*models.PrebuildConfig{ + prebuild1.Id: prebuild1, + } + + s.workspaceTemplateStore = workspacetemplate_internal.NewInMemoryWorkspaceTemplateStore() + s.workspaceTemplateService = workspacetemplates.NewWorkspaceTemplateService(workspacetemplates.WorkspaceTemplateServiceConfig{ + ConfigStore: s.workspaceTemplateStore, + FindNewestBuild: func(ctx context.Context, prebuildId string) (*services.BuildDTO, error) { + return s.buildService.Find(&services.BuildFilter{ + StoreFilter: stores.BuildFilter{ + PrebuildIds: &[]string{prebuildId}, + GetNewest: util.Pointer(true), + }, + }) + }, + ListSuccessfulBuilds: func(ctx context.Context) ([]*services.BuildDTO, error) { + return s.buildService.List(&services.BuildFilter{ + StateNames: &[]models.ResourceStateName{models.ResourceStateNameRunSuccessful}, + }) + }, + CreateBuild: func(ctx context.Context, workspaceTemplate *models.WorkspaceTemplate, repo *gitprovider.GitRepository, prebuildId string) error { + createBuildDto := services.CreateBuildDTO{ + WorkspaceTemplateName: workspaceTemplate.Name, + Branch: repo.Branch, + PrebuildId: &prebuildId, + EnvVars: workspaceTemplate.EnvVars, + } + + _, err := s.buildService.Create(createBuildDto) + return err + }, + DeleteBuilds: func(ctx context.Context, id, prebuildId *string, force bool) []error { + var prebuildIds *[]string + if prebuildId != nil { + prebuildIds = &[]string{*prebuildId} + } + + return s.buildService.Delete(&services.BuildFilter{ + StoreFilter: stores.BuildFilter{ + Id: id, + PrebuildIds: prebuildIds, + }, + }, force) + }, + GetRepositoryContext: func(ctx context.Context, url string) (repo *gitprovider.GitRepository, gitProviderId string, err error) { + gitProvider, gitProviderId, err := s.gitProviderService.GetGitProviderForUrl(url) + if err != nil { + return nil, "", err + } + + repo, err = gitProvider.GetRepositoryContext(gitprovider.GetRepositoryContext{ + Url: url, + }) + + return repo, gitProviderId, err + }, + FindPrebuildWebhook: func(ctx context.Context, gitProviderId string, repo *gitprovider.GitRepository, endpointUrl string) (*string, error) { + return s.gitProviderService.GetPrebuildWebhook(gitProviderId, repo, endpointUrl) + }, + UnregisterPrebuildWebhook: func(ctx context.Context, gitProviderId string, repo *gitprovider.GitRepository, id string) error { + return s.gitProviderService.UnregisterPrebuildWebhook(gitProviderId, repo, id) + }, + RegisterPrebuildWebhook: func(ctx context.Context, gitProviderId string, repo *gitprovider.GitRepository, endpointUrl string) (string, error) { + return s.gitProviderService.RegisterPrebuildWebhook(gitProviderId, repo, endpointUrl) + }, + GetCommitsRange: func(ctx context.Context, repo *gitprovider.GitRepository, initialSha string, currentSha string) (int, error) { + gitProvider, _, err := s.gitProviderService.GetGitProviderForUrl(repo.Url) + if err != nil { + return 0, err + } + + return gitProvider.GetCommitsRange(repo, initialSha, currentSha) + }, + }) + + for _, wt := range expectedWorkspaceTemplates { + _ = s.workspaceTemplateStore.Save(context.TODO(), wt) + } +} + +func TestWorkspaceTemplateService(t *testing.T) { + suite.Run(t, NewConfigServiceTestSuite()) +} + +func (s *WorkspaceTemplateServiceTestSuite) TestList() { + require := s.Require() + + workspaceTemplates, err := s.workspaceTemplateService.List(context.TODO(), nil) + require.Nil(err) + require.ElementsMatch(expectedWorkspaceTemplates, workspaceTemplates) +} + +func (s *WorkspaceTemplateServiceTestSuite) TestFind() { + require := s.Require() + + workspaceTemplate, err := s.workspaceTemplateService.Find(context.TODO(), &stores.WorkspaceTemplateFilter{ + Name: &workspaceTemplate1.Name, + }) + require.Nil(err) + require.Equal(workspaceTemplate1, workspaceTemplate) +} +func (s *WorkspaceTemplateServiceTestSuite) TestSetDefault() { + require := s.Require() + + err := s.workspaceTemplateService.SetDefault(context.TODO(), workspaceTemplate2.Name) + require.Nil(err) + + workspaceTemplate, err := s.workspaceTemplateService.Find(context.TODO(), &stores.WorkspaceTemplateFilter{ + Url: util.Pointer(workspaceTemplate1.RepositoryUrl), + Default: util.Pointer(true), + }) + require.Nil(err) + + require.Equal(workspaceTemplate2, workspaceTemplate) +} + +func (s *WorkspaceTemplateServiceTestSuite) TestSave() { + expectedWorkspaceTemplates = append(expectedWorkspaceTemplates, workspaceTemplate4) + + require := s.Require() + + err := s.workspaceTemplateService.Save(context.TODO(), workspaceTemplate4) + require.Nil(err) + + workspaceTemplates, err := s.workspaceTemplateService.List(context.TODO(), nil) + require.Nil(err) + require.ElementsMatch(expectedWorkspaceTemplates, workspaceTemplates) +} + +func (s *WorkspaceTemplateServiceTestSuite) TestDelete() { + expectedWorkspaceTemplates = expectedWorkspaceTemplates[:2] + + require := s.Require() + + err := s.workspaceTemplateService.Delete(context.TODO(), workspaceTemplate3.Name, false) + require.Nil(err) + + workspaceTemplates, errs := s.workspaceTemplateService.List(context.TODO(), nil) + require.Nil(errs) + require.ElementsMatch(expectedWorkspaceTemplates, workspaceTemplates) +} + +func (s *WorkspaceTemplateServiceTestSuite) AfterTest(_, _ string) { + s.gitProviderService.AssertExpectations(s.T()) + s.gitProviderService.ExpectedCalls = nil + s.buildService.AssertExpectations(s.T()) + s.buildService.ExpectedCalls = nil + s.gitProvider.AssertExpectations(s.T()) + s.gitProvider.ExpectedCalls = nil +} diff --git a/pkg/services/api_key.go b/pkg/services/api_key.go new file mode 100644 index 0000000000..8991e2c728 --- /dev/null +++ b/pkg/services/api_key.go @@ -0,0 +1,25 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package services + +import ( + "context" + + "github.com/daytonaio/daytona/pkg/models" +) + +type IApiKeyService interface { + ListClientKeys(ctx context.Context) ([]*ApiKeyDTO, error) + Create(ctx context.Context, keyType models.ApiKeyType, name string) (string, error) + Delete(ctx context.Context, name string) error + + GetApiKeyType(ctx context.Context, apiKey string) (models.ApiKeyType, error) + GetApiKeyName(ctx context.Context, apiKey string) (string, error) + IsValidApiKey(ctx context.Context, apiKey string) bool +} + +type ApiKeyDTO struct { + Type models.ApiKeyType `json:"type" validate:"required"` + Name string `json:"name" validate:"required"` +} // @name ApiKeyDTO diff --git a/pkg/services/build.go b/pkg/services/build.go new file mode 100644 index 0000000000..3970c1b0b4 --- /dev/null +++ b/pkg/services/build.go @@ -0,0 +1,51 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package services + +import ( + "context" + "errors" + "io" + + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/stores" +) + +type IBuildService interface { + List(ctx context.Context, filter *BuildFilter) ([]*BuildDTO, error) + Find(ctx context.Context, filter *BuildFilter) (*BuildDTO, error) + Create(ctx context.Context, createBuildDTO CreateBuildDTO) (string, error) + Delete(ctx context.Context, filter *BuildFilter, force bool) []error + + UpdateLastJob(ctx context.Context, buildId, jobId string) error + HandleSuccessfulRemoval(ctx context.Context, id string) error + GetBuildLogReader(ctx context.Context, buildId string) (io.Reader, error) + GetBuildLogWriter(ctx context.Context, buildId string) (io.WriteCloser, error) +} + +type BuildDTO struct { + models.Build + State models.ResourceState `json:"state" validate:"required"` +} // @name BuildDTO + +type CreateBuildDTO struct { + WorkspaceTemplateName string `json:"workspaceTemplateName" validate:"required"` + Branch string `json:"branch" validate:"required"` + PrebuildId *string `json:"prebuildId" validate:"optional"` + EnvVars map[string]string `json:"envVars" validate:"required"` +} // @name CreateBuildDTO + +type BuildFilter struct { + StateNames *[]models.ResourceStateName + ShowDeleted bool + StoreFilter stores.BuildFilter +} + +var ( + ErrBuildDeleted = errors.New("build is deleted") +) + +func IsBuildDeleted(err error) bool { + return err.Error() == ErrBuildDeleted.Error() +} diff --git a/pkg/services/env.go b/pkg/services/env.go new file mode 100644 index 0000000000..84687f1b43 --- /dev/null +++ b/pkg/services/env.go @@ -0,0 +1,47 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package services + +import ( + "context" + "strings" + + "github.com/daytonaio/daytona/pkg/models" +) + +type IEnvironmentVariableService interface { + List(ctx context.Context) ([]*models.EnvironmentVariable, error) + Map(ctx context.Context) (EnvironmentVariables, error) + Save(ctx context.Context, environmentVariable *models.EnvironmentVariable) error + Delete(ctx context.Context, key string) error +} + +type EnvironmentVariables map[string]string + +func (e EnvironmentVariables) FindContainerRegistry(server string) *models.ContainerRegistry { + for key, value := range e { + if strings.HasSuffix(key, "CONTAINER_REGISTRY_SERVER") && value == server { + usernameKey := strings.ReplaceAll(key, "SERVER", "USERNAME") + passwordKey := strings.ReplaceAll(key, "SERVER", "PASSWORD") + + return &models.ContainerRegistry{ + Server: server, + Username: e[usernameKey], + Password: e[passwordKey], + } + } + } + + return nil +} + +func (e EnvironmentVariables) FindContainerRegistryByImageName(image string) *models.ContainerRegistry { + parts := strings.Split(image, "/") + + if len(parts) < 3 { + return e.FindContainerRegistry("docker.io") + } + + return e.FindContainerRegistry(parts[0]) +} diff --git a/pkg/services/git_provider.go b/pkg/services/git_provider.go new file mode 100644 index 0000000000..7f04e86bd0 --- /dev/null +++ b/pkg/services/git_provider.go @@ -0,0 +1,34 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package services + +import ( + "context" + "net/http" + + "github.com/daytonaio/daytona/pkg/gitprovider" + "github.com/daytonaio/daytona/pkg/models" +) + +type IGitProviderService interface { + ListConfigs(ctx context.Context) ([]*models.GitProviderConfig, error) + ListConfigsForUrl(ctx context.Context, url string) ([]*models.GitProviderConfig, error) + FindConfig(ctx context.Context, id string) (*models.GitProviderConfig, error) + SaveConfig(ctx context.Context, providerConfig *models.GitProviderConfig) error + DeleteConfig(ctx context.Context, id string) error + + GetGitProvider(ctx context.Context, id string) (gitprovider.GitProvider, error) + GetGitProviderForUrl(ctx context.Context, url string) (gitprovider.GitProvider, string, error) + GetGitProviderForHttpRequest(ctx context.Context, req *http.Request) (gitprovider.GitProvider, error) + GetGitUser(ctx context.Context, gitProviderId string) (*gitprovider.GitUser, error) + GetNamespaces(ctx context.Context, gitProviderId string, options gitprovider.ListOptions) ([]*gitprovider.GitNamespace, error) + GetRepoBranches(ctx context.Context, gitProviderId string, namespaceId string, repositoryId string, options gitprovider.ListOptions) ([]*gitprovider.GitBranch, error) + GetRepoPRs(ctx context.Context, gitProviderId string, namespaceId string, repositoryId string, options gitprovider.ListOptions) ([]*gitprovider.GitPullRequest, error) + GetRepositories(ctx context.Context, gitProviderId string, namespaceId string, options gitprovider.ListOptions) ([]*gitprovider.GitRepository, error) + GetLastCommitSha(ctx context.Context, repo *gitprovider.GitRepository) (string, error) + + RegisterPrebuildWebhook(ctx context.Context, gitProviderId string, repo *gitprovider.GitRepository, endpointUrl string) (string, error) + GetPrebuildWebhook(ctx context.Context, gitProviderId string, repo *gitprovider.GitRepository, endpointUrl string) (*string, error) + UnregisterPrebuildWebhook(ctx context.Context, gitProviderId string, repo *gitprovider.GitRepository, id string) error +} diff --git a/pkg/services/job.go b/pkg/services/job.go new file mode 100644 index 0000000000..6f3b5e0f44 --- /dev/null +++ b/pkg/services/job.go @@ -0,0 +1,28 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package services + +import ( + "context" + "errors" + + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/stores" +) + +type IJobService interface { + List(ctx context.Context, filter *stores.JobFilter) ([]*models.Job, error) + Find(ctx context.Context, filter *stores.JobFilter) (*models.Job, error) + Create(ctx context.Context, job *models.Job) error + UpdateState(ctx context.Context, jobId string, updateJobStateDto UpdateJobStateDTO) error + Delete(ctx context.Context, job *models.Job) error +} + +var ( + ErrInvalidResourceJobAction = errors.New("invalid job action for resource") +) + +func IsInvalidResourceJobAction(err error) bool { + return err.Error() == ErrInvalidResourceJobAction.Error() +} diff --git a/pkg/services/runner.go b/pkg/services/runner.go new file mode 100644 index 0000000000..0efada8e1d --- /dev/null +++ b/pkg/services/runner.go @@ -0,0 +1,72 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package services + +import ( + "context" + "errors" + "io" + + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/os" +) + +type IRunnerService interface { + List(ctx context.Context) ([]*RunnerDTO, error) + Find(ctx context.Context, runnerId string) (*RunnerDTO, error) + Create(ctx context.Context, req CreateRunnerDTO) (*RunnerDTO, error) + Delete(ctx context.Context, runnerId string) error + + UpdateMetadata(ctx context.Context, runnerId string, metadata *models.RunnerMetadata) error + UpdateJobState(ctx context.Context, jobId string, req UpdateJobStateDTO) error + ListRunnerJobs(ctx context.Context, runnerId string) ([]*models.Job, error) + + ListProviders(ctx context.Context, runnerId *string) ([]models.ProviderInfo, error) + ListProvidersForInstall(ctx context.Context, serverRegistryUrl string) ([]ProviderDTO, error) + InstallProvider(ctx context.Context, runnerId, name, version, serverRegistryUrl string) error + UninstallProvider(ctx context.Context, runnerId string, name string) error + UpdateProvider(ctx context.Context, runnerId, name, version, serverRegistryUrl string) error + + GetRunnerLogReader(ctx context.Context, runnerId string) (io.Reader, error) + GetRunnerLogWriter(ctx context.Context, runnerId string) (io.WriteCloser, error) +} + +type RunnerDTO struct { + models.Runner + State models.ResourceState `json:"state" validate:"required"` +} // @name RunnerDTO + +type CreateRunnerDTO struct { + Id string `json:"id" validate:"required"` + Name string `json:"name" validate:"required"` +} // @name CreateRunnerDTO + +type CreateRunnerResultDTO struct { + models.Runner + ApiKey string `json:"apiKey" validate:"required"` +} // @name CreateRunnerResultDTO + +type UpdateJobStateDTO struct { + State models.JobState `json:"state" validate:"required"` + ErrorMessage *string `json:"errorMessage,omitempty" validate:"optional"` +} // @name UpdateJobState + +type ProviderDTO struct { + Name string `json:"name" validate:"required"` + Label *string `json:"label" validate:"optional"` + Version string `json:"version" validate:"required"` + Latest bool `json:"latest" validate:"required"` +} // @name ProviderDTO + +type ProviderMetadata struct { + Name string `json:"name" validate:"required"` + Version string `json:"version" validate:"required"` + DownloadUrls DownloadUrls `json:"downloadUrls" validate:"required"` +} + +type DownloadUrls map[os.OperatingSystem]string + +var ( + ErrRunnerAlreadyExists = errors.New("runner already exists") +) diff --git a/pkg/services/target.go b/pkg/services/target.go new file mode 100644 index 0000000000..9da6f644f0 --- /dev/null +++ b/pkg/services/target.go @@ -0,0 +1,64 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package services + +import ( + "context" + "errors" + "io" + + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/stores" +) + +type ITargetService interface { + List(ctx context.Context, filter *stores.TargetFilter, params TargetRetrievalParams) ([]TargetDTO, error) + Find(ctx context.Context, filter *stores.TargetFilter, params TargetRetrievalParams) (*TargetDTO, error) + Create(ctx context.Context, req CreateTargetDTO) (*models.Target, error) + Save(ctx context.Context, target *models.Target) error + Start(ctx context.Context, targetId string) error + Stop(ctx context.Context, targetId string) error + Restart(ctx context.Context, targetId string) error + SetDefault(ctx context.Context, targetId string) error + Delete(ctx context.Context, targetId string) error + ForceDelete(ctx context.Context, targetId string) error + + UpdateMetadata(ctx context.Context, targetId string, metadata *models.TargetMetadata) (*models.TargetMetadata, error) + UpdateProviderMetadata(ctx context.Context, targetId, metadata string) error + UpdateLastJob(ctx context.Context, targetId, jobId string) error + + HandleSuccessfulCreation(ctx context.Context, targetId string) error + GetTargetLogReader(ctx context.Context, targetId string) (io.Reader, error) + GetTargetLogWriter(ctx context.Context, targetId string) (io.WriteCloser, error) +} + +type TargetDTO struct { + models.Target + State models.ResourceState `json:"state" validate:"required"` +} // @name TargetDTO + +type CreateTargetDTO struct { + Id string `json:"id" validate:"required"` + Name string `json:"name" validate:"required"` + TargetConfigId string `json:"targetConfigId" validate:"required"` +} // @name CreateTargetDTO + +type UpdateTargetProviderMetadataDTO struct { + Metadata string `json:"metadata" validate:"required"` +} // @name UpdateTargetProviderMetadataDTO + +type TargetRetrievalParams struct { + ShowDeleted bool +} + +var ( + ErrTargetAlreadyExists = errors.New("target already exists") + ErrInvalidTargetName = errors.New("name is not a valid alphanumeric string") + ErrTargetDeleted = errors.New("target is deleted") + ErrAgentlessTarget = errors.New("provider uses an agentless target") +) + +func IsTargetDeleted(err error) bool { + return errors.Is(err, ErrTargetDeleted) +} diff --git a/pkg/services/target_config.go b/pkg/services/target_config.go new file mode 100644 index 0000000000..9fc58a375f --- /dev/null +++ b/pkg/services/target_config.go @@ -0,0 +1,24 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package services + +import ( + "context" + + "github.com/daytonaio/daytona/pkg/models" +) + +type CreateTargetConfigDTO struct { + Name string `json:"name" validate:"required"` + ProviderInfo models.ProviderInfo `json:"providerInfo" validate:"required"` + Options string `json:"options" validate:"required"` +} // @name CreateTargetConfigDTO + +type ITargetConfigService interface { + List(ctx context.Context) ([]*models.TargetConfig, error) + Map(ctx context.Context) (map[string]*models.TargetConfig, error) + Find(ctx context.Context, idOrName string) (*models.TargetConfig, error) + Create(ctx context.Context, targetConfig CreateTargetConfigDTO) (*models.TargetConfig, error) + Delete(ctx context.Context, targetConfigId string) error +} diff --git a/pkg/services/workspace.go b/pkg/services/workspace.go new file mode 100644 index 0000000000..f12fc17ac5 --- /dev/null +++ b/pkg/services/workspace.go @@ -0,0 +1,93 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package services + +import ( + "context" + "errors" + "io" + + "github.com/daytonaio/daytona/pkg/gitprovider" + "github.com/daytonaio/daytona/pkg/models" +) + +type IWorkspaceService interface { + List(ctx context.Context, params WorkspaceRetrievalParams) ([]WorkspaceDTO, error) + Find(ctx context.Context, workspaceId string, params WorkspaceRetrievalParams) (*WorkspaceDTO, error) + Create(ctx context.Context, req CreateWorkspaceDTO) (*WorkspaceDTO, error) + Start(ctx context.Context, workspaceId string) error + Stop(ctx context.Context, workspaceId string) error + Delete(ctx context.Context, workspaceId string) error + ForceDelete(ctx context.Context, workspaceId string) error + Restart(ctx context.Context, workspaceId string) error + + UpdateMetadata(ctx context.Context, workspaceId string, metadata *models.WorkspaceMetadata) (*models.WorkspaceMetadata, error) + UpdateProviderMetadata(ctx context.Context, workspaceId, metadata string) error + UpdateLastJob(ctx context.Context, workspaceId, jobId string) error + UpdateLabels(ctx context.Context, workspaceId string, labels map[string]string) (*WorkspaceDTO, error) + + GetWorkspaceLogReader(ctx context.Context, workspaceId string) (io.Reader, error) + GetWorkspaceLogWriter(ctx context.Context, workspaceId string) (io.WriteCloser, error) +} + +type WorkspaceDTO struct { + models.Workspace + State models.ResourceState `json:"state" validate:"required"` +} // @name WorkspaceDTO + +type CreateWorkspaceDTO struct { + Id string `json:"id" validate:"required"` + Name string `json:"name" validate:"required"` + Image *string `json:"image,omitempty" validate:"optional"` + User *string `json:"user,omitempty" validate:"optional"` + BuildConfig *models.BuildConfig `json:"buildConfig,omitempty" validate:"optional"` + Source CreateWorkspaceSourceDTO `json:"source" validate:"required"` + EnvVars map[string]string `json:"envVars" validate:"required"` + Labels map[string]string `json:"labels" validate:"required"` + TargetId string `json:"targetId" validate:"required"` + GitProviderConfigId *string `json:"gitProviderConfigId,omitempty" validate:"optional"` +} // @name CreateWorkspaceDTO + +func (c *CreateWorkspaceDTO) ToWorkspace() *models.Workspace { + w := &models.Workspace{ + Id: c.Id, + Name: c.Name, + BuildConfig: c.BuildConfig, + Repository: c.Source.Repository, + EnvVars: c.EnvVars, + TargetId: c.TargetId, + GitProviderConfigId: c.GitProviderConfigId, + Labels: c.Labels, + } + + if c.Image != nil { + w.Image = *c.Image + } + + if c.User != nil { + w.User = *c.User + } + + return w +} + +type CreateWorkspaceSourceDTO struct { + Repository *gitprovider.GitRepository `json:"repository" validate:"required"` +} // @name CreateWorkspaceSourceDTO + +type WorkspaceRetrievalParams struct { + ShowDeleted bool + Labels map[string]string +} + +var ( + ErrWorkspaceAlreadyExists = errors.New("workspace already exists") + ErrWorkspaceDeleted = errors.New("workspace is deleted") + ErrInvalidWorkspaceName = errors.New("workspace name is not valid. Only [a-zA-Z0-9-_.] are allowed") + ErrInvalidWorkspaceTemplate = errors.New("workspace template is invalid") +) + +func IsWorkspaceDeleted(err error) bool { + return errors.Is(err, ErrWorkspaceDeleted) +} diff --git a/pkg/services/workspace_template.go b/pkg/services/workspace_template.go new file mode 100644 index 0000000000..859f569f22 --- /dev/null +++ b/pkg/services/workspace_template.go @@ -0,0 +1,56 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package services + +import ( + "context" + + "github.com/daytonaio/daytona/pkg/gitprovider" + "github.com/daytonaio/daytona/pkg/models" + "github.com/daytonaio/daytona/pkg/stores" +) + +type IWorkspaceTemplateService interface { + List(ctx context.Context, filter *stores.WorkspaceTemplateFilter) ([]*models.WorkspaceTemplate, error) + Find(ctx context.Context, filter *stores.WorkspaceTemplateFilter) (*models.WorkspaceTemplate, error) + Save(ctx context.Context, workspaceTemplate *models.WorkspaceTemplate) error + SetDefault(ctx context.Context, workspaceTemplateName string) error + Delete(ctx context.Context, workspaceTemplateName string, force bool) []error + + ListPrebuilds(ctx context.Context, workspaceTemplateFilter *stores.WorkspaceTemplateFilter, prebuildFilter *stores.PrebuildFilter) ([]*PrebuildDTO, error) + FindPrebuild(ctx context.Context, workspaceTemplateFilter *stores.WorkspaceTemplateFilter, prebuildFilter *stores.PrebuildFilter) (*PrebuildDTO, error) + SavePrebuild(ctx context.Context, workspaceTemplateName string, createPrebuildDto CreatePrebuildDTO) (*PrebuildDTO, error) + DeletePrebuild(ctx context.Context, workspaceTemplateName string, id string, force bool) []error + + StartRetentionPoller(ctx context.Context) error + EnforceRetentionPolicy(ctx context.Context) error + ProcessGitEvent(ctx context.Context, gitEventData gitprovider.GitEventData) error +} + +type CreateWorkspaceTemplateDTO struct { + Name string `json:"name" validate:"required"` + Image *string `json:"image,omitempty" validate:"optional"` + User *string `json:"user,omitempty" validate:"optional"` + BuildConfig *models.BuildConfig `json:"buildConfig,omitempty" validate:"optional"` + RepositoryUrl string `json:"repositoryUrl" validate:"required"` + EnvVars map[string]string `json:"envVars" validate:"required"` + GitProviderConfigId *string `json:"gitProviderConfigId" validate:"optional"` +} // @name CreateWorkspaceTemplateDTO + +type PrebuildDTO struct { + Id string `json:"id" validate:"required"` + WorkspaceTemplateName string `json:"workspaceTemplateName" validate:"required"` + Branch string `json:"branch" validate:"required"` + CommitInterval *int `json:"commitInterval" validate:"optional"` + TriggerFiles []string `json:"triggerFiles" validate:"optional"` + Retention int `json:"retention" validate:"required"` +} // @name PrebuildDTO + +type CreatePrebuildDTO struct { + Id *string `json:"id" validate:"optional"` + Branch string `json:"branch" validate:"optional"` + CommitInterval *int `json:"commitInterval" validate:"optional"` + TriggerFiles []string `json:"triggerFiles" validate:"optional"` + Retention int `json:"retention" validate:"required"` +} // @name CreatePrebuildDTO diff --git a/pkg/stores/api_key.go b/pkg/stores/api_key.go new file mode 100644 index 0000000000..bb1a4522e0 --- /dev/null +++ b/pkg/stores/api_key.go @@ -0,0 +1,28 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package stores + +import ( + "context" + "errors" + + "github.com/daytonaio/daytona/pkg/models" +) + +type ApiKeyStore interface { + IStore + List(ctx context.Context) ([]*models.ApiKey, error) + Find(ctx context.Context, key string) (*models.ApiKey, error) + FindByName(ctx context.Context, name string) (*models.ApiKey, error) + Save(ctx context.Context, apiKey *models.ApiKey) error + Delete(ctx context.Context, apiKey *models.ApiKey) error +} + +var ( + ErrApiKeyNotFound = errors.New("api key not found") +) + +func IsApiKeyNotFound(err error) bool { + return err.Error() == ErrApiKeyNotFound.Error() +} diff --git a/pkg/stores/build.go b/pkg/stores/build.go new file mode 100644 index 0000000000..1b119d7a5e --- /dev/null +++ b/pkg/stores/build.go @@ -0,0 +1,45 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package stores + +import ( + "context" + "errors" + + "github.com/daytonaio/daytona/pkg/models" +) + +type BuildStore interface { + IStore + List(ctx context.Context, filter *BuildFilter) ([]*models.Build, error) + Find(ctx context.Context, filter *BuildFilter) (*models.Build, error) + Save(ctx context.Context, build *models.Build) error + Delete(ctx context.Context, id string) error +} + +var ( + ErrBuildNotFound = errors.New("build not found") +) + +func IsBuildNotFound(err error) bool { + return err.Error() == ErrBuildNotFound.Error() +} + +type BuildFilter struct { + Id *string + PrebuildIds *[]string + GetNewest *bool + BuildConfig *models.BuildConfig + RepositoryUrl *string + Branch *string + EnvVars *map[string]string +} + +func (f *BuildFilter) PrebuildIdsToInterface() []interface{} { + args := make([]interface{}, len(*f.PrebuildIds)) + for i, v := range *f.PrebuildIds { + args[i] = v + } + return args +} diff --git a/pkg/stores/env.go b/pkg/stores/env.go new file mode 100644 index 0000000000..7ab93e0d92 --- /dev/null +++ b/pkg/stores/env.go @@ -0,0 +1,26 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package stores + +import ( + "context" + "errors" + + "github.com/daytonaio/daytona/pkg/models" +) + +type EnvironmentVariableStore interface { + IStore + List(ctx context.Context) ([]*models.EnvironmentVariable, error) + Save(ctx context.Context, environmentVariable *models.EnvironmentVariable) error + Delete(ctx context.Context, key string) error +} + +var ( + ErrEnvironmentVariableNotFound = errors.New("environment variable not found") +) + +func IsEnvironmentVariableNotFound(err error) bool { + return err.Error() == ErrEnvironmentVariableNotFound.Error() +} diff --git a/pkg/stores/git_provider.go b/pkg/stores/git_provider.go new file mode 100644 index 0000000000..8b96770927 --- /dev/null +++ b/pkg/stores/git_provider.go @@ -0,0 +1,27 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package stores + +import ( + "context" + "errors" + + "github.com/daytonaio/daytona/pkg/models" +) + +type GitProviderConfigStore interface { + IStore + List(ctx context.Context) ([]*models.GitProviderConfig, error) + Find(ctx context.Context, id string) (*models.GitProviderConfig, error) + Save(ctx context.Context, gpc *models.GitProviderConfig) error + Delete(ctx context.Context, gpc *models.GitProviderConfig) error +} + +var ( + ErrGitProviderConfigNotFound = errors.New("git provider config not found") +) + +func IsGitProviderNotFound(err error) bool { + return err.Error() == ErrGitProviderConfigNotFound.Error() +} diff --git a/pkg/stores/job_store.go b/pkg/stores/job_store.go new file mode 100644 index 0000000000..ce3994ceec --- /dev/null +++ b/pkg/stores/job_store.go @@ -0,0 +1,57 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package stores + +import ( + "context" + "errors" + + "github.com/daytonaio/daytona/pkg/models" +) + +type JobStore interface { + IStore + List(ctx context.Context, filter *JobFilter) ([]*models.Job, error) + Find(ctx context.Context, filter *JobFilter) (*models.Job, error) + Save(ctx context.Context, job *models.Job) error + Delete(ctx context.Context, job *models.Job) error +} + +type JobFilter struct { + Id *string + ResourceId *string + RunnerIdOrIsNil *string + ResourceType *models.ResourceType + States *[]models.JobState + Actions *[]models.JobAction +} + +func (f *JobFilter) StatesToInterface() []interface{} { + args := make([]interface{}, len(*f.States)) + for i, v := range *f.States { + args[i] = v + } + return args +} + +func (f *JobFilter) ActionsToInterface() []interface{} { + args := make([]interface{}, len(*f.Actions)) + for i, v := range *f.Actions { + args[i] = v + } + return args +} + +var ( + ErrJobNotFound = errors.New("job not found") + ErrJobInProgress = errors.New("another job is in progress") +) + +func IsJobNotFound(err error) bool { + return err.Error() == ErrJobNotFound.Error() +} + +func IsJobInProgress(err error) bool { + return err.Error() == ErrJobInProgress.Error() +} diff --git a/pkg/stores/runner.go b/pkg/stores/runner.go new file mode 100644 index 0000000000..bdcd3f7b07 --- /dev/null +++ b/pkg/stores/runner.go @@ -0,0 +1,27 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package stores + +import ( + "context" + "errors" + + "github.com/daytonaio/daytona/pkg/models" +) + +type RunnerStore interface { + IStore + List(ctx context.Context) ([]*models.Runner, error) + Find(ctx context.Context, idOrName string) (*models.Runner, error) + Save(ctx context.Context, runner *models.Runner) error + Delete(ctx context.Context, runner *models.Runner) error +} + +var ( + ErrRunnerNotFound = errors.New("runner not found") +) + +func IsRunnerNotFound(err error) bool { + return err.Error() == ErrRunnerNotFound.Error() +} diff --git a/pkg/stores/runner_metadata.go b/pkg/stores/runner_metadata.go new file mode 100644 index 0000000000..d2ab2943d0 --- /dev/null +++ b/pkg/stores/runner_metadata.go @@ -0,0 +1,27 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package stores + +import ( + "context" + "errors" + + "github.com/daytonaio/daytona/pkg/models" +) + +type RunnerMetadataStore interface { + IStore + List(ctx context.Context) ([]*models.RunnerMetadata, error) + Find(ctx context.Context, runnerId string) (*models.RunnerMetadata, error) + Save(ctx context.Context, metadata *models.RunnerMetadata) error + Delete(ctx context.Context, metadata *models.RunnerMetadata) error +} + +var ( + ErrRunnerMetadataNotFound = errors.New("runner metadata not found") +) + +func IsRunnerMetadataNotFound(err error) bool { + return err.Error() == ErrRunnerMetadataNotFound.Error() +} diff --git a/pkg/stores/store.go b/pkg/stores/store.go new file mode 100644 index 0000000000..f38b868c5e --- /dev/null +++ b/pkg/stores/store.go @@ -0,0 +1,30 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package stores + +import ( + "context" + + log "github.com/sirupsen/logrus" +) + +type TransactionKey struct{} + +type IStore interface { + BeginTransaction(ctx context.Context) (context.Context, error) + CommitTransaction(ctx context.Context) error + // If an error ocurrs while rolling back the transaction, the error should be wrapped and returned, + // otherwise, the original error is returned + RollbackTransaction(ctx context.Context, err error) error +} + +func RecoverAndRollback(ctx context.Context, store IStore) { + if r := recover(); r != nil { + err := store.RollbackTransaction(ctx, nil) + if err != nil { + // TODO: Think about this + log.Error(err) + } + } +} diff --git a/pkg/stores/target.go b/pkg/stores/target.go new file mode 100644 index 0000000000..b89d1d3717 --- /dev/null +++ b/pkg/stores/target.go @@ -0,0 +1,32 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package stores + +import ( + "context" + "errors" + + "github.com/daytonaio/daytona/pkg/models" +) + +type TargetFilter struct { + IdOrName *string + Default *bool +} + +type TargetStore interface { + IStore + List(ctx context.Context, filter *TargetFilter) ([]*models.Target, error) + Find(ctx context.Context, filter *TargetFilter) (*models.Target, error) + Save(ctx context.Context, target *models.Target) error + Delete(ctx context.Context, target *models.Target) error +} + +var ( + ErrTargetNotFound = errors.New("target not found") +) + +func IsTargetNotFound(err error) bool { + return err.Error() == ErrTargetNotFound.Error() +} diff --git a/pkg/stores/target_config.go b/pkg/stores/target_config.go new file mode 100644 index 0000000000..3aba29dfb1 --- /dev/null +++ b/pkg/stores/target_config.go @@ -0,0 +1,27 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package stores + +import ( + "context" + "errors" + + "github.com/daytonaio/daytona/pkg/models" +) + +type TargetConfigStore interface { + IStore + List(ctx context.Context, allowDeleted bool) ([]*models.TargetConfig, error) + Find(ctx context.Context, idOrName string, allowDeleted bool) (*models.TargetConfig, error) + Save(ctx context.Context, targetConfig *models.TargetConfig) error +} + +var ( + ErrTargetConfigNotFound = errors.New("target config not found") + ErrTargetConfigAlreadyExists = errors.New("target config with the same name already exists") +) + +func IsTargetConfigNotFound(err error) bool { + return err.Error() == ErrTargetConfigNotFound.Error() +} diff --git a/pkg/stores/target_metadata.go b/pkg/stores/target_metadata.go new file mode 100644 index 0000000000..52196d3ea5 --- /dev/null +++ b/pkg/stores/target_metadata.go @@ -0,0 +1,26 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package stores + +import ( + "context" + "errors" + + "github.com/daytonaio/daytona/pkg/models" +) + +type TargetMetadataStore interface { + IStore + Find(ctx context.Context, targetId string) (*models.TargetMetadata, error) + Save(ctx context.Context, metadata *models.TargetMetadata) error + Delete(ctx context.Context, metadata *models.TargetMetadata) error +} + +var ( + ErrTargetMetadataNotFound = errors.New("target metadata not found") +) + +func IsTargetMetadataNotFound(err error) bool { + return err.Error() == ErrTargetMetadataNotFound.Error() +} diff --git a/pkg/stores/workspace.go b/pkg/stores/workspace.go new file mode 100644 index 0000000000..0c75c2a4be --- /dev/null +++ b/pkg/stores/workspace.go @@ -0,0 +1,27 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package stores + +import ( + "context" + "errors" + + "github.com/daytonaio/daytona/pkg/models" +) + +type WorkspaceStore interface { + IStore + List(ctx context.Context) ([]*models.Workspace, error) + Find(ctx context.Context, idOrName string) (*models.Workspace, error) + Save(ctx context.Context, workspace *models.Workspace) error + Delete(ctx context.Context, workspace *models.Workspace) error +} + +var ( + ErrWorkspaceNotFound = errors.New("workspace not found") +) + +func IsWorkspaceNotFound(err error) bool { + return err.Error() == ErrWorkspaceNotFound.Error() +} diff --git a/pkg/stores/workspace_metadata.go b/pkg/stores/workspace_metadata.go new file mode 100644 index 0000000000..a5f4474309 --- /dev/null +++ b/pkg/stores/workspace_metadata.go @@ -0,0 +1,26 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package stores + +import ( + "context" + "errors" + + "github.com/daytonaio/daytona/pkg/models" +) + +type WorkspaceMetadataStore interface { + IStore + Find(ctx context.Context, workspaceId string) (*models.WorkspaceMetadata, error) + Save(ctx context.Context, metadata *models.WorkspaceMetadata) error + Delete(ctx context.Context, metadata *models.WorkspaceMetadata) error +} + +var ( + ErrWorkspaceMetadataNotFound = errors.New("workspace metadata not found") +) + +func IsWorkspaceMetadataNotFound(err error) bool { + return err.Error() == ErrWorkspaceMetadataNotFound.Error() +} diff --git a/pkg/stores/workspace_template.go b/pkg/stores/workspace_template.go new file mode 100644 index 0000000000..ddba3d8e3a --- /dev/null +++ b/pkg/stores/workspace_template.go @@ -0,0 +1,48 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package stores + +import ( + "context" + "errors" + + "github.com/daytonaio/daytona/pkg/models" +) + +type WorkspaceTemplateFilter struct { + Name *string + Url *string + Default *bool + PrebuildId *string + GitProviderConfigId *string +} + +type PrebuildFilter struct { + WorkspaceTemplateName *string + Id *string + Branch *string + CommitInterval *int + TriggerFiles *[]string +} + +type WorkspaceTemplateStore interface { + IStore + List(ctx context.Context, filter *WorkspaceTemplateFilter) ([]*models.WorkspaceTemplate, error) + Find(ctx context.Context, filter *WorkspaceTemplateFilter) (*models.WorkspaceTemplate, error) + Save(ctx context.Context, workspaceTemplate *models.WorkspaceTemplate) error + Delete(ctx context.Context, workspaceTemplate *models.WorkspaceTemplate) error +} + +var ( + ErrWorkspaceTemplateNotFound = errors.New("workspace template not found") + ErrPrebuildNotFound = errors.New("prebuild not found") +) + +func IsWorkspaceTemplateNotFound(err error) bool { + return err.Error() == ErrWorkspaceTemplateNotFound.Error() +} + +func IsPrebuildNotFound(err error) bool { + return err.Error() == ErrPrebuildNotFound.Error() +} diff --git a/pkg/tailscale/forward_unix.go b/pkg/tailscale/forward_unix.go index 1d31bd458d..ee06842d88 100644 --- a/pkg/tailscale/forward_unix.go +++ b/pkg/tailscale/forward_unix.go @@ -12,7 +12,6 @@ import ( ) type ForwardConfig struct { - Ctx context.Context TsnetConn *tsnet.Server Hostname string SshPort int @@ -20,7 +19,7 @@ type ForwardConfig struct { RemoteSock string } -func ForwardRemoteUnixSock(config ForwardConfig) (chan bool, chan error) { +func ForwardRemoteUnixSock(ctx context.Context, config ForwardConfig) (chan bool, chan error) { sshTun := tunnel.NewUnix(config.TsnetConn, config.LocalSock, config.Hostname, config.SshPort, config.RemoteSock) errChan := make(chan error) @@ -44,7 +43,7 @@ func ForwardRemoteUnixSock(config ForwardConfig) (chan bool, chan error) { }) go func() { - errChan <- sshTun.Start(config.Ctx) + errChan <- sshTun.Start(ctx) }() return startedChann, errChan diff --git a/pkg/telemetry/api_key.go b/pkg/telemetry/api_key.go new file mode 100644 index 0000000000..a0f24929d0 --- /dev/null +++ b/pkg/telemetry/api_key.go @@ -0,0 +1,40 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package telemetry + +import "github.com/daytonaio/daytona/pkg/models" + +type ApiKeyEventName string + +const ( + ApiKeyEventLifecycleCreated ApiKeyEventName = "api_key_lifecycle_created" + ApiKeyEventLifecycleCreationFailed ApiKeyEventName = "api_key_lifecycle_creation_failed" +) + +type ApiKeyEvent struct { + key *models.ApiKey + AbstractEvent +} + +func NewApiKeyEvent(name ApiKeyEventName, key *models.ApiKey, err error, extras map[string]interface{}) Event { + return ApiKeyEvent{ + key: key, + AbstractEvent: AbstractEvent{ + name: string(name), + extras: extras, + err: err, + }, + } +} + +func (e ApiKeyEvent) Props() map[string]interface{} { + props := e.AbstractEvent.Props() + + if e.key == nil { + return props + } + + props["type"] = e.key.Type + return props +} diff --git a/pkg/telemetry/build.go b/pkg/telemetry/build.go new file mode 100644 index 0000000000..021261cd83 --- /dev/null +++ b/pkg/telemetry/build.go @@ -0,0 +1,55 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package telemetry + +import "github.com/daytonaio/daytona/pkg/models" + +type BuildEventName string + +const ( + BuildEventLifecycleCreated BuildEventName = "build_lifecycle_created" + BuildEventLifecycleCreationFailed BuildEventName = "build_lifecycle_creation_failed" + BuildEventLifecycleDeleted BuildEventName = "build_lifecycle_deleted" + BuildEventLifecycleDeletionFailed BuildEventName = "build_lifecycle_deletion_failed" + BuildEventLifecycleForceDeleted BuildEventName = "build_lifecycle_force_deleted" + BuildEventLifecycleForceDeletionFailed BuildEventName = "build_lifecycle_force_deletion_failed" +) + +type buildEvent struct { + build *models.Build + AbstractEvent +} + +func NewBuildEvent(name BuildEventName, b *models.Build, err error, extras map[string]interface{}) Event { + return buildEvent{ + build: b, + AbstractEvent: AbstractEvent{ + name: string(name), + extras: extras, + err: err, + }, + } +} + +func (e buildEvent) Props() map[string]interface{} { + props := e.AbstractEvent.Props() + + if e.build == nil { + return props + } + + props["build_id"] = e.build.Id + props["from_prebuild"] = e.build.PrebuildId != nil && *e.build.PrebuildId != "" + if isImagePublic(e.build.ContainerConfig.Image) { + props["image"] = e.build.Image + } + + if e.build.Repository != nil && isPublic(e.build.Repository.Url) { + props["repository_url"] = e.build.Repository.Url + } + + props["builder"] = getBuilder(e.build.BuildConfig) + + return props +} diff --git a/pkg/telemetry/build_runner_events.go b/pkg/telemetry/build_runner_events.go deleted file mode 100644 index cc5dad8e52..0000000000 --- a/pkg/telemetry/build_runner_events.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package telemetry - -import ( - "context" -) - -type BuildRunnerEvent string - -const ( - // Purge events - BuildRunnerEventPurgeStarted BuildRunnerEvent = "build_runner_purge_started" - BuildRunnerEventPurgeCompleted BuildRunnerEvent = "build_runner_purge_completed" - BuildRunnerEventPurgeError BuildRunnerEvent = "build_runner_purge_error" - - // Build events - BuildRunnerEventRunBuild BuildRunnerEvent = "build_runner_run_build" - BuildRunnerEventRunBuildError BuildRunnerEvent = "build_runner_run_build_error" -) - -func NewBuildRunnerEventProps(ctx context.Context, buildId, buildState string) map[string]interface{} { - props := map[string]interface{}{} - - sessionId := SessionId(ctx) - serverId := ServerId(ctx) - - props["session_id"] = sessionId - props["server_id"] = serverId - - props["build_id"] = buildId - props["build_state"] = buildState - - return props -} diff --git a/pkg/telemetry/cli.go b/pkg/telemetry/cli.go new file mode 100644 index 0000000000..1588a77810 --- /dev/null +++ b/pkg/telemetry/cli.go @@ -0,0 +1,67 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package telemetry + +import ( + "strings" + + "github.com/spf13/cobra" +) + +type CliEventName string + +const ( + CliEventCommandStarted CliEventName = "cli_command_started" + CliEventCommandCompleted CliEventName = "cli_command_completed" + CliEventCommandFailed CliEventName = "cli_command_failed" + CliEventCommandInvalid CliEventName = "cli_command_invalid" + CliEventCommandInterrupted CliEventName = "cli_command_interrupted" + CliEventTargetOpened CliEventName = "cli_target_opened" + CliEventTargetOpenFailed CliEventName = "cli_target_open_failed" + CliEventWorkspaceOpened CliEventName = "cli_workspace_opened" + CliEventWorkspaceOpenFailed CliEventName = "cli_workspace_open_failed" + CliEventDefaultIdeSet CliEventName = "cli_default_ide_set" +) + +type cliEvent struct { + AbstractEvent + cmd *cobra.Command + flags []string +} + +func NewCliEvent(name CliEventName, cmd *cobra.Command, flags []string, err error, extras map[string]interface{}) Event { + return cliEvent{ + AbstractEvent: AbstractEvent{ + name: string(name), + extras: extras, + err: err, + }, + cmd: cmd, + flags: flags, + } +} + +func (e cliEvent) Props() map[string]interface{} { + props := e.AbstractEvent.Props() + + if e.cmd == nil { + return props + } + + path := e.cmd.CommandPath() + + // Trim daytona from the path if a non-root command was invoked + // This prevents a `daytona` pileup in the telemetry data + if path != "daytona" { + path = strings.TrimPrefix(path, "daytona ") + } + + calledAs := e.cmd.CalledAs() + + props["command"] = path + props["called_as"] = calledAs + props["flags"] = e.flags + + return props +} diff --git a/pkg/telemetry/cli_events.go b/pkg/telemetry/cli_events.go deleted file mode 100644 index 175e9b9225..0000000000 --- a/pkg/telemetry/cli_events.go +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package telemetry - -type CliEvent string - -const ( - CliEventCmdStart CliEvent = "cli_cmd_start" - CliEventCmdEnd CliEvent = "cli_cmd_end" - CliEventInvalidCmd CliEvent = "cli_invalid_cmd" -) - -var AdditionalData map[string]interface{} = map[string]interface{}{} diff --git a/pkg/telemetry/constants.go b/pkg/telemetry/constants.go index b2d38df4b7..57d3b3e0f8 100644 --- a/pkg/telemetry/constants.go +++ b/pkg/telemetry/constants.go @@ -20,7 +20,9 @@ var ( type TelemetrySource string var ( - CLI_SOURCE TelemetrySource = "cli" - CLI_PROJECT_SOURCE TelemetrySource = "cli-project" - AGENT_SOURCE TelemetrySource = "agent" + CLI_SOURCE TelemetrySource = "cli" + CLI_AGENT_MODE_SOURCE TelemetrySource = "cli_agent_mode" + AGENT_SOURCE TelemetrySource = "agent" + RUNNER_SOURCE TelemetrySource = "runner" + SERVER_SOURCE TelemetrySource = "server" ) diff --git a/pkg/telemetry/event.go b/pkg/telemetry/event.go new file mode 100644 index 0000000000..d7e48080f0 --- /dev/null +++ b/pkg/telemetry/event.go @@ -0,0 +1,32 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package telemetry + +type Event interface { + Name() string + Props() map[string]interface{} +} + +type AbstractEvent struct { + name string + extras map[string]interface{} + err error +} + +func (e AbstractEvent) Name() string { + return e.name +} + +func (e AbstractEvent) Props() map[string]interface{} { + props := map[string]interface{}{} + if e.err != nil { + props["error"] = e.err.Error() + } + + for k, v := range e.extras { + props[k] = v + } + + return props +} diff --git a/pkg/telemetry/git_provider_config.go b/pkg/telemetry/git_provider_config.go new file mode 100644 index 0000000000..b90a1bd9fc --- /dev/null +++ b/pkg/telemetry/git_provider_config.go @@ -0,0 +1,49 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package telemetry + +import "github.com/daytonaio/daytona/pkg/models" + +type GitProviderConfigEventName string + +const ( + GitProviderConfigEventLifecycleSaved GitProviderConfigEventName = "git_provider_config_lifecycle_saved" + GitProviderConfigEventLifecycleSaveFailed GitProviderConfigEventName = "git_provider_config_lifecycle_save_failed" + GitProviderConfigEventLifecycleDeleted GitProviderConfigEventName = "git_provider_config_lifecycle_deleted" + GitProviderConfigEventLifecycleDeletionFailed GitProviderConfigEventName = "git_provider_config_lifecycle_deletion_failed" + GitProviderConfigEventLifecycleForceDeleted GitProviderConfigEventName = "git_provider_config_lifecycle_force_deleted" + GitProviderConfigEventLifecycleForceDeletionFailed GitProviderConfigEventName = "git_provider_config_lifecycle_force_deletion_failed" +) + +type GitProviderConfigEvent struct { + gitProviderConfig *models.GitProviderConfig + AbstractEvent +} + +func NewGitProviderConfigEvent(name GitProviderConfigEventName, b *models.GitProviderConfig, err error, extras map[string]interface{}) Event { + return GitProviderConfigEvent{ + gitProviderConfig: b, + AbstractEvent: AbstractEvent{ + name: string(name), + extras: extras, + err: err, + }, + } +} + +func (e GitProviderConfigEvent) Props() map[string]interface{} { + props := e.AbstractEvent.Props() + + if e.gitProviderConfig == nil { + return props + } + + props["provider_id"] = e.gitProviderConfig.ProviderId + props["is_self_hosted"] = e.gitProviderConfig.BaseApiUrl != nil && *e.gitProviderConfig.BaseApiUrl != "" + if e.gitProviderConfig.SigningMethod != nil { + props["signing_method"] = *e.gitProviderConfig.SigningMethod + } + + return props +} diff --git a/pkg/telemetry/job.go b/pkg/telemetry/job.go new file mode 100644 index 0000000000..2a369c1c32 --- /dev/null +++ b/pkg/telemetry/job.go @@ -0,0 +1,54 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package telemetry + +import ( + "github.com/daytonaio/daytona/pkg/common" + "github.com/daytonaio/daytona/pkg/models" +) + +type JobEventName string + +const ( + JobEventLifecycleCreated JobEventName = "job_lifecycle_created" + JobEventLifecycleCreationFailed JobEventName = "job_lifecycle_creation_failed" + JobEventRunStarted JobEventName = "job_run_started" + JobEventRunCompleted JobEventName = "job_run_completed" + JobEventRunFailed JobEventName = "job_run_failed" +) + +type jobEvent struct { + AbstractEvent + job *models.Job +} + +func NewJobEvent(name JobEventName, j *models.Job, err error, extras map[string]interface{}) Event { + return jobEvent{ + job: j, + AbstractEvent: AbstractEvent{ + name: string(name), + extras: extras, + err: err, + }, + } +} + +func (e jobEvent) Props() map[string]interface{} { + props := e.AbstractEvent.Props() + + if e.job == nil { + return props + } + + props["job_id"] = e.job.Id + props["is_local_runner"] = e.job.RunnerId != nil && *e.job.RunnerId == common.LOCAL_RUNNER_ID + props["resource_type"] = e.job.ResourceType + props["job_action"] = e.job.Action + + if e.job.Error != nil { + props["job_error"] = *e.job.Error + } + + return props +} diff --git a/pkg/telemetry/runner.go b/pkg/telemetry/runner.go new file mode 100644 index 0000000000..9238a8e622 --- /dev/null +++ b/pkg/telemetry/runner.go @@ -0,0 +1,53 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package telemetry + +import ( + "github.com/daytonaio/daytona/pkg/common" + "github.com/daytonaio/daytona/pkg/models" +) + +type RunnerEventName string + +const ( + RunnerEventLifecycleRegistered RunnerEventName = "runner_lifecycle_registered" + RunnerEventLifecycleRegistrationFailed RunnerEventName = "runner_lifecycle_registration_failed" + RunnerEventLifecycleDeleted RunnerEventName = "runner_lifecycle_deleted" + RunnerEventLifecycleDeletionFailed RunnerEventName = "runner_lifecycle_deletion_failed" + RunnerEventProviderInstalled RunnerEventName = "runner_provider_installed" + RunnerEventProviderInstallationFailed RunnerEventName = "runner_provider_installation_failed" + RunnerEventProviderUninstalled RunnerEventName = "runner_provider_uninstalled" + RunnerEventProviderUninstallationFailed RunnerEventName = "runer_provider_uninstallation_failed" + RunnerEventProviderUpdated RunnerEventName = "runner_provider_updated" + RunnerEventProviderUpdateFailed RunnerEventName = "runner_provider_update_failed" +) + +type runnerEvent struct { + AbstractEvent + runner *models.Runner +} + +func NewRunnerEvent(name RunnerEventName, r *models.Runner, err error, extras map[string]interface{}) Event { + return runnerEvent{ + runner: r, + AbstractEvent: AbstractEvent{ + name: string(name), + extras: extras, + err: err, + }, + } +} + +func (e runnerEvent) Props() map[string]interface{} { + props := e.AbstractEvent.Props() + + if e.runner == nil { + return props + } + + props["runner_id"] = e.runner.Id + props["is_local_runner"] = e.runner.Id == common.LOCAL_RUNNER_ID + + return props +} diff --git a/pkg/telemetry/server_events.go b/pkg/telemetry/server_events.go deleted file mode 100644 index c32b006445..0000000000 --- a/pkg/telemetry/server_events.go +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package telemetry - -import ( - "context" - "net/http" - "strings" - "time" - - "github.com/daytonaio/daytona/pkg/provider" - "github.com/daytonaio/daytona/pkg/workspace" -) - -type ServerEvent string - -const ( - ServerEventApiRequestStarted ServerEvent = "server_api_request_started" - ServerEventApiResponseSent ServerEvent = "server_api_response_sent" - ServerEventPurgeStarted ServerEvent = "server_purge_started" - ServerEventPurgeCompleted ServerEvent = "server_purge_completed" - ServerEventPurgeError ServerEvent = "server_purge_error" - - // Workspace events - ServerEventWorkspaceCreated ServerEvent = "server_workspace_created" - ServerEventWorkspaceDestroyed ServerEvent = "server_workspace_destroyed" - ServerEventWorkspaceStarted ServerEvent = "server_workspace_started" - ServerEventWorkspaceStopped ServerEvent = "server_workspace_stopped" - ServerEventWorkspaceCreateError ServerEvent = "server_workspace_created_error" - ServerEventWorkspaceDestroyError ServerEvent = "server_workspace_destroyed_error" - ServerEventWorkspaceStartError ServerEvent = "server_workspace_started_error" - ServerEventWorkspaceStopError ServerEvent = "server_workspace_stopped_error" -) - -func NewWorkspaceEventProps(ctx context.Context, workspace *workspace.Workspace, target *provider.ProviderTarget) map[string]interface{} { - props := map[string]interface{}{} - - sessionId := SessionId(ctx) - serverId := ServerId(ctx) - - props["session_id"] = sessionId - props["server_id"] = serverId - - if workspace != nil { - props["workspace_id"] = workspace.Id - props["workspace_n_projects"] = len(workspace.Projects) - publicRepos := []string{} - publicImages := []string{} - builders := map[string]int{} - - for _, project := range workspace.Projects { - if isImagePublic(project.Image) { - publicImages = append(publicImages, project.Image) - } - if project.Repository != nil && isPublic(project.Repository.Url) { - publicRepos = append(publicRepos, project.Repository.Url) - } - if project.BuildConfig == nil { - builders["none"]++ - } else if project.BuildConfig.Devcontainer != nil { - builders["devcontainer"]++ - } else { - builders["automatic"]++ - } - } - - props["workspace_public_repos"] = publicRepos - props["workspace_public_images"] = publicImages - props["workspace_builders"] = builders - } - - if target != nil { - props["target_name"] = target.Name - props["target_provider"] = target.ProviderInfo.Name - props["target_provider_version"] = target.ProviderInfo.Version - } - - return props -} - -func isImagePublic(imageName string) bool { - if strings.Count(imageName, "/") < 2 { - if strings.Count(imageName, "/") == 0 { - return isPublic("https://hub.docker.com/_/" + imageName) - } - - return isPublic("https://hub.docker.com/r/" + imageName) - } - - return isPublic(imageName) -} - -func isPublic(url string) bool { - ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond) - _, err := http.NewRequestWithContext(ctx, "HEAD", url, nil) - cancel() - return err == nil -} diff --git a/pkg/telemetry/target.go b/pkg/telemetry/target.go new file mode 100644 index 0000000000..18edcd2d02 --- /dev/null +++ b/pkg/telemetry/target.go @@ -0,0 +1,60 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package telemetry + +import ( + "github.com/daytonaio/daytona/pkg/common" + "github.com/daytonaio/daytona/pkg/models" +) + +type TargetEventName string + +const ( + TargetEventLifecycleCreated TargetEventName = "target_lifecycle_created" + TargetEventLifecycleCreationFailed TargetEventName = "target_lifecycle_creation_failed" + TargetEventLifecycleStarted TargetEventName = "target_lifecycle_started" + TargetEventLifecycleStartFailed TargetEventName = "target_lifecycle_start_failed" + TargetEventLifecycleRestarted TargetEventName = "target_lifecycle_restarted" + TargetEventLifecycleRestartFailed TargetEventName = "target_lifecycle_restart_failed" + TargetEventLifecycleStopped TargetEventName = "target_lifecycle_stopped" + TargetEventLifecycleStopFailed TargetEventName = "target_lifecycle_stop_failed" + TargetEventLifecycleDeleted TargetEventName = "target_lifecycle_deleted" + TargetEventLifecycleDeletionFailed TargetEventName = "target_lifecycle_deletion_failed" + TargetEventLifecycleForceDeleted TargetEventName = "target_lifecycle_force_deleted" + TargetEventLifecycleForceDeletionFailed TargetEventName = "target_lifecycle_force_deletion_failed" +) + +type targetEvent struct { + AbstractEvent + target *models.Target +} + +func NewTargetEvent(name TargetEventName, t *models.Target, err error, extras map[string]interface{}) Event { + return targetEvent{ + target: t, + AbstractEvent: AbstractEvent{ + name: string(name), + extras: extras, + err: err, + }, + } +} + +func (e targetEvent) Props() map[string]interface{} { + props := e.AbstractEvent.Props() + + if e.target == nil { + return props + } + + props["target_id"] = e.target.Id + props["is_local_docker_target_config"] = common.IsLocalDockerTarget(e.target.TargetConfig.ProviderInfo.Name, e.target.TargetConfig.Options, e.target.TargetConfig.ProviderInfo.RunnerId) + props["provider_name"] = e.target.TargetConfig.ProviderInfo.Name + props["provider_version"] = e.target.TargetConfig.ProviderInfo.Version + props["target_config_deleted"] = e.target.TargetConfig.Deleted + props["agentless_target"] = e.target.TargetConfig.ProviderInfo.AgentlessTarget + props["is_local_runner"] = e.target.TargetConfig.ProviderInfo.RunnerId == common.LOCAL_RUNNER_ID + + return props +} diff --git a/pkg/telemetry/target_config.go b/pkg/telemetry/target_config.go new file mode 100644 index 0000000000..9674eaa2ac --- /dev/null +++ b/pkg/telemetry/target_config.go @@ -0,0 +1,51 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package telemetry + +import ( + "github.com/daytonaio/daytona/pkg/common" + "github.com/daytonaio/daytona/pkg/models" +) + +type TargetConfigEventName string + +const ( + TargetConfigEventLifecycleCreated TargetConfigEventName = "target_config_lifecycle_created" + TargetConfigEventLifecycleCreationFailed TargetConfigEventName = "target_config_lifecycle_creation_failed" + TargetConfigEventLifecycleDeleted TargetConfigEventName = "target_config_lifecycle_deleted" + TargetConfigEventLifecycleDeletionFailed TargetConfigEventName = "target_config_lifecycle_deletion_failed" +) + +type targetConfigEvent struct { + AbstractEvent + targetConfig *models.TargetConfig +} + +func NewTargetConfigEvent(name TargetConfigEventName, tc *models.TargetConfig, err error, extras map[string]interface{}) Event { + return targetConfigEvent{ + targetConfig: tc, + AbstractEvent: AbstractEvent{ + name: string(name), + extras: extras, + err: err, + }, + } +} + +func (e targetConfigEvent) Props() map[string]interface{} { + props := e.AbstractEvent.Props() + + if e.targetConfig == nil { + return props + } + + props["target_config_id"] = e.targetConfig.Id + props["provider_name"] = e.targetConfig.ProviderInfo.Name + props["provider_version"] = e.targetConfig.ProviderInfo.Version + props["deleted"] = e.targetConfig.Deleted + props["is_local_docker_target_config"] = common.IsLocalDockerTarget(e.targetConfig.ProviderInfo.Name, e.targetConfig.Options, e.targetConfig.ProviderInfo.RunnerId) + props["is_local_runner"] = e.targetConfig.ProviderInfo.RunnerId == common.LOCAL_RUNNER_ID + + return props +} diff --git a/pkg/telemetry/telemetry.go b/pkg/telemetry/telemetry.go index 171cc9cb5a..6fa07779ae 100644 --- a/pkg/telemetry/telemetry.go +++ b/pkg/telemetry/telemetry.go @@ -7,6 +7,10 @@ import ( "context" "fmt" "io" + "net/http" + "runtime" + "strings" + "time" "github.com/daytonaio/daytona/internal" "github.com/google/uuid" @@ -14,10 +18,7 @@ import ( type TelemetryService interface { io.Closer - TrackCliEvent(event CliEvent, clientId string, properties map[string]interface{}) error - TrackServerEvent(event ServerEvent, clientId string, properties map[string]interface{}) error - TrackBuildRunnerEvent(event BuildRunnerEvent, clientId string, properties map[string]interface{}) error - SetCommonProps(properties map[string]interface{}) + Track(event Event, clientId string) error } func TelemetryEnabled(ctx context.Context) bool { @@ -58,17 +59,28 @@ func ServerId(ctx context.Context) string { return id } -type AbstractTelemetryService struct { - daytonaVersion string - TelemetryService +func SetCommonProps(version string, source TelemetrySource, properties map[string]interface{}) { + properties["daytona_version"] = version + properties["source"] = source + properties["os"] = runtime.GOOS + properties["arch"] = runtime.GOARCH } -func NewAbstractTelemetryService(version string) *AbstractTelemetryService { - return &AbstractTelemetryService{ - daytonaVersion: version, +func isImagePublic(imageName string) bool { + if strings.Count(imageName, "/") < 2 { + if strings.Count(imageName, "/") == 0 { + return isPublic("https://hub.docker.com/_/" + imageName) + } + + return isPublic("https://hub.docker.com/r/" + imageName) } + + return isPublic(imageName) } -func (t *AbstractTelemetryService) SetCommonProps(properties map[string]interface{}) { - properties["daytona_version"] = t.daytonaVersion +func isPublic(url string) bool { + ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond) + _, err := http.NewRequestWithContext(ctx, "HEAD", url, nil) + cancel() + return err == nil } diff --git a/pkg/telemetry/workspace.go b/pkg/telemetry/workspace.go new file mode 100644 index 0000000000..3b2cca818e --- /dev/null +++ b/pkg/telemetry/workspace.go @@ -0,0 +1,78 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package telemetry + +import ( + "github.com/daytonaio/daytona/pkg/common" + "github.com/daytonaio/daytona/pkg/models" +) + +type WorkspaceEventName string + +const ( + WorkspaceEventLifecycleCreated WorkspaceEventName = "workspace_lifecycle_created" + WorkspaceEventLifecycleCreationFailed WorkspaceEventName = "workspace_lifecycle_creation_failed" + WorkspaceEventLifecycleStarted WorkspaceEventName = "workspace_lifecycle_started" + WorkspaceEventLifecycleStartFailed WorkspaceEventName = "workspace_lifecycle_start_failed" + WorkspaceEventLifecycleRestarted WorkspaceEventName = "workspace_lifecycle_restarted" + WorkspaceEventLifecycleRestartFailed WorkspaceEventName = "workspace_lifecycle_restart_failed" + WorkspaceEventLifecycleStopped WorkspaceEventName = "workspace_lifecycle_stopped" + WorkspaceEventLifecycleStopFailed WorkspaceEventName = "workspace_lifecycle_stop_failed" + WorkspaceEventLifecycleDeleted WorkspaceEventName = "workspace_lifecycle_deleted" + WorkspaceEventLifecycleDeletionFailed WorkspaceEventName = "workspace_lifecycle_deletion_failed" + WorkspaceEventLifecycleForceDeleted WorkspaceEventName = "workspace_lifecycle_force_deleted" + WorkspaceEventLifecycleForceDeletionFailed WorkspaceEventName = "workspace_lifecycle_force_deletion_failed" + WorkspaceEventLabelsUpdated WorkspaceEventName = "workspace_labels_updated" + WorkspaceEventLabelsUpdateFailed WorkspaceEventName = "workspace_label_update_failed" +) + +type workspaceEvent struct { + AbstractEvent + workspace *models.Workspace +} + +func NewWorkspaceEvent(name WorkspaceEventName, w *models.Workspace, err error, extras map[string]interface{}) Event { + return workspaceEvent{ + workspace: w, + AbstractEvent: AbstractEvent{ + name: string(name), + extras: extras, + err: err, + }, + } +} + +func (e workspaceEvent) Props() map[string]interface{} { + props := e.AbstractEvent.Props() + + if e.workspace == nil { + return props + } + + props["workspace_id"] = e.workspace.Id + props["is_local_docker_target_config"] = common.IsLocalDockerTarget(e.workspace.Target.TargetConfig.ProviderInfo.Name, e.workspace.Target.TargetConfig.Options, e.workspace.Target.TargetConfig.ProviderInfo.RunnerId) + props["provider_name"] = e.workspace.Target.TargetConfig.ProviderInfo.Name + props["provider_version"] = e.workspace.Target.TargetConfig.ProviderInfo.Version + if isImagePublic(e.workspace.Image) { + props["image"] = e.workspace.Image + } + if e.workspace.Repository != nil && isPublic(e.workspace.Repository.Url) { + props["repository_url"] = e.workspace.Repository.Url + } + props["builder"] = getBuilder(e.workspace.BuildConfig) + props["is_local_runner"] = e.workspace.Target.TargetConfig.ProviderInfo.RunnerId == common.LOCAL_RUNNER_ID + props["n_labels"] = len(e.workspace.Labels) + + return props +} + +func getBuilder(bc *models.BuildConfig) string { + if bc == nil { + return "none" + } else if bc.Devcontainer != nil { + return "devcontainer" + } else { + return "automatic" + } +} diff --git a/pkg/telemetry/workspace_template.go b/pkg/telemetry/workspace_template.go new file mode 100644 index 0000000000..033e9171b5 --- /dev/null +++ b/pkg/telemetry/workspace_template.go @@ -0,0 +1,60 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package telemetry + +import ( + "github.com/daytonaio/daytona/pkg/models" +) + +type WorkspaceTemplateEventName string + +var ( + WorkspaceTemplateEventLifecycleSaved WorkspaceTemplateEventName = "workspace_template_lifecycle_saved" + WorkspaceTemplateEventLifecycleSaveFailed WorkspaceTemplateEventName = "workspace_template_lifecycle_save_failed" + WorkspaceTemplateEventLifecycleDeleted WorkspaceTemplateEventName = "workspace_template_lifecycle_deleted" + WorkspaceTemplateEventLifecycleDeletionFailed WorkspaceTemplateEventName = "workspace_template_lifecycle_deletion_failed" + WorkspaceTemplateEventPrebuildSaved WorkspaceTemplateEventName = "workspace_template_prebuild_saved" + WorkspaceTemplateEventPrebuildSaveFailed WorkspaceTemplateEventName = "workspace_template_prebuild_save_failed" + WorkspaceTemplateEventPrebuildDeleted WorkspaceTemplateEventName = "workspace_template_prebuild_deleted" + WorkspaceTemplateEventPrebuildDeletionFailed WorkspaceTemplateEventName = "workspace_template_prebuild_deletion_failed" +) + +type workspaceTemplateEvent struct { + AbstractEvent + workspaceTemplate *models.WorkspaceTemplate +} + +func NewWorkspaceTemplateEvent(name WorkspaceTemplateEventName, wt *models.WorkspaceTemplate, err error, extras map[string]interface{}) Event { + return workspaceTemplateEvent{ + workspaceTemplate: wt, + AbstractEvent: AbstractEvent{ + name: string(name), + extras: extras, + err: err, + }, + } +} + +func (e workspaceTemplateEvent) Props() map[string]interface{} { + props := e.AbstractEvent.Props() + + if e.workspaceTemplate == nil { + return props + } + + props["workspace_template_name"] = e.workspaceTemplate.Name + props["prebuilds"] = e.workspaceTemplate.Prebuilds + + if isImagePublic(e.workspaceTemplate.Image) { + props["image"] = e.workspaceTemplate.Image + } + + if isPublic(e.workspaceTemplate.RepositoryUrl) { + props["repository_url"] = e.workspaceTemplate.RepositoryUrl + } + + props["builder"] = getBuilder(e.workspaceTemplate.BuildConfig) + + return props +} diff --git a/pkg/views/apikey/create.go b/pkg/views/apikey/create.go index 9e8e5d4520..6108d76850 100644 --- a/pkg/views/apikey/create.go +++ b/pkg/views/apikey/create.go @@ -13,7 +13,7 @@ import ( "github.com/charmbracelet/huh" ) -func ApiKeyCreationView(name *string, clientKeys []apiclient.ApiKey) { +func ApiKeyCreationView(name *string, clientKeys []apiclient.ApiKeyViewDTO) { form := huh.NewForm( huh.NewGroup( huh.NewInput(). diff --git a/pkg/views/apikey/list.go b/pkg/views/apikey/list.go index 002d20cfbc..e589b3834b 100644 --- a/pkg/views/apikey/list.go +++ b/pkg/views/apikey/list.go @@ -16,7 +16,7 @@ type RowData struct { Type string } -func ListApiKeys(apiKeyList []apiclient.ApiKey) { +func ListApiKeys(apiKeyList []apiclient.ApiKeyViewDTO) { data := [][]string{} for _, apiKey := range apiKeyList { @@ -32,7 +32,7 @@ func ListApiKeys(apiKeyList []apiclient.ApiKey) { fmt.Println(table) } -func getRowFromRowData(apiKey apiclient.ApiKey) []string { +func getRowFromRowData(apiKey apiclient.ApiKeyViewDTO) []string { rowData := RowData{"", ""} rowData.Name = apiKey.Name @@ -46,7 +46,7 @@ func getRowFromRowData(apiKey apiclient.ApiKey) []string { return row } -func renderUnstyledList(apiKeyList []apiclient.ApiKey) { +func renderUnstyledList(apiKeyList []apiclient.ApiKeyViewDTO) { output := "\n" for _, apiKey := range apiKeyList { diff --git a/pkg/views/apikey/notify.go b/pkg/views/apikey/notify.go index 20ac01a437..e36c731316 100644 --- a/pkg/views/apikey/notify.go +++ b/pkg/views/apikey/notify.go @@ -23,7 +23,7 @@ func Render(key, apiUrl string) { views.RenderContainerLayout(views.GetInfoMessage(output)) - command := fmt.Sprintf("daytona profile add -a %s -k %s", apiUrl, key) + command := fmt.Sprintf("daytona profile create -a %s -k %s", apiUrl, key) fmt.Println(lipgloss.NewStyle().Padding(0).Foreground(views.Green).Render(command)) if err := clipboard.WriteAll(command); err == nil { diff --git a/pkg/views/apikey/select.go b/pkg/views/apikey/select.go index 393a01afe9..6bf3363559 100644 --- a/pkg/views/apikey/select.go +++ b/pkg/views/apikey/select.go @@ -13,7 +13,7 @@ import ( var NewApiKeyName = "+ New API Key" -func GetApiKeyFromPrompt(apiKeys []apiclient.ApiKey, title string, withNewApiKey bool) (*apiclient.ApiKey, error) { +func GetApiKeyFromPrompt(apiKeys []apiclient.ApiKeyViewDTO, title string, withNewApiKey bool) (*apiclient.ApiKeyViewDTO, error) { var items []list.Item for _, p := range apiKeys { @@ -25,7 +25,7 @@ func GetApiKeyFromPrompt(apiKeys []apiclient.ApiKey, title string, withNewApiKey if withNewApiKey { name := NewApiKeyName items = append(items, item{ - apiKey: apiclient.ApiKey{ + apiKey: apiclient.ApiKeyViewDTO{ Name: name, }, }) diff --git a/pkg/views/apikey/view.go b/pkg/views/apikey/view.go index 229c57441b..4178686149 100644 --- a/pkg/views/apikey/view.go +++ b/pkg/views/apikey/view.go @@ -14,7 +14,7 @@ import ( ) type item struct { - apiKey apiclient.ApiKey + apiKey apiclient.ApiKeyViewDTO } func (i item) Title() string { return i.apiKey.Name } @@ -25,7 +25,7 @@ func (i item) FilterValue() string { return i.apiKey.Name } type model struct { list list.Model - choice *apiclient.ApiKey + choice *apiclient.ApiKeyViewDTO } func (m model) Init() tea.Cmd { diff --git a/pkg/views/build/info/view.go b/pkg/views/build/info/view.go index 96acfb87ea..e5a6adf396 100644 --- a/pkg/views/build/info/view.go +++ b/pkg/views/build/info/view.go @@ -11,8 +11,8 @@ import ( "github.com/daytonaio/daytona/internal/util" "github.com/daytonaio/daytona/pkg/apiclient" "github.com/daytonaio/daytona/pkg/views" - projectconfig_info "github.com/daytonaio/daytona/pkg/views/projectconfig/info" views_util "github.com/daytonaio/daytona/pkg/views/util" + workspacetemplate_info "github.com/daytonaio/daytona/pkg/views/workspacetemplate/info" "golang.org/x/term" ) @@ -25,7 +25,7 @@ var propertyValueStyle = lipgloss.NewStyle(). Foreground(views.Light). Bold(true) -func Render(b *apiclient.Build, apiServerConfig *apiclient.ServerConfig, forceUnstyled bool) { +func Render(b *apiclient.BuildDTO, apiServerConfig *apiclient.ServerConfig, forceUnstyled bool) { var output string output += "\n\n" @@ -33,7 +33,7 @@ func Render(b *apiclient.Build, apiServerConfig *apiclient.ServerConfig, forceUn output += getInfoLine("ID", b.Id) + "\n" - output += getInfoLine("State", string(b.State)) + "\n" + output += getInfoLine("State", views.GetStateLabel(b.State.Name)) + "\n" output += getInfoLine("Repository", b.Repository.Url) + "\n" @@ -45,15 +45,15 @@ func Render(b *apiclient.Build, apiServerConfig *apiclient.ServerConfig, forceUn output += getInfoLine("User", *b.User) + "\n" } - if projectconfig_info.GetLabelFromBuild(b.BuildConfig) != "" { - projectDefaults := &views_util.ProjectConfigDefaults{ - Image: &apiServerConfig.DefaultProjectImage, - ImageUser: &apiServerConfig.DefaultProjectUser, + if workspacetemplate_info.GetLabelFromBuild(b.BuildConfig) != "" { + workspaceDefaults := &views_util.WorkspaceTemplateDefaults{ + Image: &apiServerConfig.DefaultWorkspaceImage, + ImageUser: &apiServerConfig.DefaultWorkspaceUser, } - _, buildChoice := views_util.GetProjectBuildChoice(apiclient.CreateProjectDTO{ + _, buildChoice := views_util.GetWorkspaceBuildChoice(apiclient.CreateWorkspaceDTO{ BuildConfig: b.BuildConfig, - }, projectDefaults) + }, workspaceDefaults) output += getInfoLine("Build", buildChoice) + "\n" } @@ -61,7 +61,9 @@ func Render(b *apiclient.Build, apiServerConfig *apiclient.ServerConfig, forceUn output += getInfoLine("Devcontainer path", b.BuildConfig.Devcontainer.FilePath) + "\n" } - output += getInfoLine("Prebuild ID", b.PrebuildId) + "\n" + if b.PrebuildId != nil { + output += getInfoLine("Prebuild ID", *b.PrebuildId) + "\n" + } output += getInfoLine("Created", util.FormatTimestamp(b.CreatedAt)) + "\n" diff --git a/pkg/views/build/list/view.go b/pkg/views/build/list/view.go index 807774ecce..ff667f3e33 100644 --- a/pkg/views/build/list/view.go +++ b/pkg/views/build/list/view.go @@ -16,13 +16,13 @@ import ( type rowData struct { Id string - State string + Status string PrebuildId string CreatedAt string UpdatedAt string } -func ListBuilds(buildList []apiclient.Build, apiServerConfig *apiclient.ServerConfig) { +func ListBuilds(buildList []apiclient.BuildDTO, apiServerConfig *apiclient.ServerConfig) { if len(buildList) == 0 { views_util.NotifyEmptyBuildList(true) return @@ -45,15 +45,19 @@ func ListBuilds(buildList []apiclient.Build, apiServerConfig *apiclient.ServerCo fmt.Println(table) } -func SortBuilds(buildList *[]apiclient.Build) { +func SortBuilds(buildList *[]apiclient.BuildDTO) { sort.Slice(*buildList, func(i, j int) bool { - b1 := (*buildList)[i] - b2 := (*buildList)[j] - return b1.UpdatedAt > b2.UpdatedAt + pi, pj := views_util.GetStateSortPriorities((*buildList)[i].State.Name, (*buildList)[j].State.Name) + if pi != pj { + return pi < pj + } + + // If two builds have the same state priority, compare the UpdatedAt property + return (*buildList)[i].State.UpdatedAt > (*buildList)[j].State.UpdatedAt }) } -func renderUnstyledList(buildList []apiclient.Build, apiServerConfig *apiclient.ServerConfig) { +func renderUnstyledList(buildList []apiclient.BuildDTO, apiServerConfig *apiclient.ServerConfig) { for _, b := range buildList { info.Render(&b, apiServerConfig, true) @@ -63,21 +67,24 @@ func renderUnstyledList(buildList []apiclient.Build, apiServerConfig *apiclient. } } -func getRowFromRowData(build apiclient.Build) []string { +func getRowFromRowData(build apiclient.BuildDTO) []string { var data rowData data.Id = build.Id + views_util.AdditionalPropertyPadding - data.State = string(build.State) - data.PrebuildId = build.PrebuildId - if data.PrebuildId == "" { + data.Status = views.GetStateLabel(build.State.Name) + + if build.PrebuildId != nil && *build.PrebuildId != "" { + data.PrebuildId = *build.PrebuildId + } else { data.PrebuildId = "/" } + data.CreatedAt = util.FormatTimestamp(build.CreatedAt) data.UpdatedAt = util.FormatTimestamp(build.UpdatedAt) return []string{ views.NameStyle.Render(data.Id), - views.DefaultRowDataStyle.Render(data.State), + views.DefaultRowDataStyle.Render(data.Status), views.DefaultRowDataStyle.Render(data.PrebuildId), views.DefaultRowDataStyle.Render(data.CreatedAt), views.DefaultRowDataStyle.Render(data.UpdatedAt), diff --git a/pkg/views/common.go b/pkg/views/common.go index d63f2d0547..da0b7788be 100644 --- a/pkg/views/common.go +++ b/pkg/views/common.go @@ -10,6 +10,7 @@ import ( "github.com/charmbracelet/huh" "github.com/charmbracelet/lipgloss" + "github.com/daytonaio/daytona/pkg/apiclient" "golang.org/x/term" ) @@ -38,8 +39,6 @@ var DefaultHorizontalMargin = 1 var TUITableMinimumWidth = 80 -var CheckmarkSymbol = lipgloss.NewStyle().Foreground(lipgloss.Color("42")).SetString("✓") - var SeparatorString = lipgloss.NewStyle().Foreground(LightGray).Render("===") var ( @@ -48,6 +47,29 @@ var ( widthBreakpoints = []int{60, 80, 100, 120, 140, 160} ) +// Resources that have actions being performed on them have a higher priority when listing +var ResourceListStatePriorities = map[apiclient.ModelsResourceStateName]int{ + apiclient.ResourceStateNamePendingRun: 1, + apiclient.ResourceStateNamePendingCreate: 1, + apiclient.ResourceStateNamePendingStart: 1, + apiclient.ResourceStateNamePendingStop: 1, + apiclient.ResourceStateNamePendingRestart: 1, + apiclient.ResourceStateNamePendingDelete: 1, + apiclient.ResourceStateNamePendingForcedDelete: 1, + apiclient.ResourceStateNameRunning: 1, + apiclient.ResourceStateNameCreating: 1, + apiclient.ResourceStateNameStarting: 1, + apiclient.ResourceStateNameStopping: 1, + apiclient.ResourceStateNameDeleting: 1, + apiclient.ResourceStateNameStarted: 2, + apiclient.ResourceStateNameRunSuccessful: 2, + apiclient.ResourceStateNameUndefined: 2, + apiclient.ResourceStateNameError: 3, + apiclient.ResourceStateNameUnresponsive: 4, + apiclient.ResourceStateNameStopped: 5, + apiclient.ResourceStateNameDeleted: 6, +} + func RenderMainTitle(title string) { fmt.Println(lipgloss.NewStyle().Foreground(Green).Bold(true).Padding(1, 0, 1, 0).Render(title)) } @@ -181,3 +203,53 @@ func GetEnvVarsInput(envVars *map[string]string) *huh.Text { return nil }) } + +// Bolds the message and prepends a checkmark +func GetPrettyLogLine(message string) string { + return fmt.Sprintf("%s \033[1m%s\033[0m\n", lipgloss.NewStyle().Foreground(lipgloss.Color("42")).SetString("✓").String(), message) +} + +func GetStateLabel(state apiclient.ModelsResourceStateName) string { + switch state { + case apiclient.ResourceStateNameUndefined: + return UndefinedStyle.Render("/") + case apiclient.ResourceStateNamePendingRun: + return PendingStyle.Render("PENDING") + case apiclient.ResourceStateNameRunning: + return RunningStyle.Render("RUNNING") + case apiclient.ResourceStateNameRunSuccessful: + return RunSuccessfulStyle.Render("SUCCESS") + case apiclient.ResourceStateNamePendingCreate: + return PendingStyle.Render("PENDING") + case apiclient.ResourceStateNameCreating: + return CreatingStyle.Render("CREATING") + case apiclient.ResourceStateNamePendingStart: + return PendingStyle.Render("STARTING") + case apiclient.ResourceStateNameStarting: + return StartingStyle.Render("STARTING") + case apiclient.ResourceStateNameStarted: + return StartedStyle.Render("STARTED") + case apiclient.ResourceStateNamePendingStop: + return PendingStyle.Render("STOPPING") + case apiclient.ResourceStateNameStopping: + return StoppingStyle.Render("STOPPING") + case apiclient.ResourceStateNameStopped: + return StoppedStyle.Render("STOPPED") + case apiclient.ResourceStateNamePendingRestart: + return DeletingStyle.Render("RESTARTING") + case apiclient.ResourceStateNamePendingDelete: + return DeletingStyle.Render("DELETING") + case apiclient.ResourceStateNamePendingForcedDelete: + return DeletingStyle.Render("DELETING") + case apiclient.ResourceStateNameDeleting: + return DeletingStyle.Render("DELETING") + case apiclient.ResourceStateNameDeleted: + return DeletedStyle.Render("DELETED") + case apiclient.ResourceStateNameError: + return ErrorStyle.Render("ERROR") + case apiclient.ResourceStateNameUnresponsive: + return UnresponsiveStyle.Render("UNRESPONSIVE") + } + + return "/" +} diff --git a/pkg/views/containerregistry/list/view.go b/pkg/views/containerregistry/list/view.go deleted file mode 100644 index 94a39abcc1..0000000000 --- a/pkg/views/containerregistry/list/view.go +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package list - -import ( - "fmt" - "strings" - - "github.com/daytonaio/daytona/pkg/apiclient" - "github.com/daytonaio/daytona/pkg/views" - views_util "github.com/daytonaio/daytona/pkg/views/util" -) - -type rowData struct { - Server string - Username string - Password string -} - -func ListRegistries(registryList []apiclient.ContainerRegistry) { - if len(registryList) == 0 { - views_util.NotifyEmptyContainerRegistryList(true) - return - } - - data := [][]string{} - - for _, registry := range registryList { - data = append(data, getRowFromData(registry)) - } - - table := views_util.GetTableView(data, []string{ - "Server", "Username", "Password", - }, nil, func() { - renderUnstyledList(registryList) - }) - - fmt.Println(table) -} - -func getRowFromData(registry apiclient.ContainerRegistry) []string { - var data rowData - - data.Server = registry.Server - data.Username = registry.Username - - row := []string{ - views.NameStyle.Render(data.Server), - views.DefaultRowDataStyle.Render(data.Username), - views.DefaultRowDataStyle.Render(strings.Repeat("*", 10)), - } - - return row -} - -func renderUnstyledList(registryList []apiclient.ContainerRegistry) { - output := "\n" - - for _, registry := range registryList { - output += fmt.Sprintf("%s %s", views.GetPropertyKey("Server: "), registry.Server) + "\n\n" - - output += fmt.Sprintf("%s %s", views.GetPropertyKey("Username: "), registry.Username) + "\n\n" - - output += fmt.Sprintf("%s %s", views.GetPropertyKey("Password: "), registry.Password) + "\n\n" - - if registry.Server != registryList[len(registryList)-1].Server { - output += views.SeparatorString + "\n\n" - } - } - - fmt.Println(output) -} diff --git a/pkg/views/containerregistry/set.go b/pkg/views/containerregistry/set.go deleted file mode 100644 index 2183a3b2f4..0000000000 --- a/pkg/views/containerregistry/set.go +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package containerregistry - -import ( - "errors" - "log" - - "github.com/charmbracelet/huh" - "github.com/daytonaio/daytona/pkg/apiclient" - "github.com/daytonaio/daytona/pkg/views" -) - -type RegistryView struct { - Server string - Username string - Password string -} - -func RegistryCreationView(registryView *RegistryView, registries []apiclient.ContainerRegistry, editing bool) { - form := huh.NewForm( - huh.NewGroup( - huh.NewInput(). - Title("Server URL"). - Value(®istryView.Server). - Validate(func(str string) error { - if str == "" { - return errors.New("server URL can not be blank") - } - return nil - }), - huh.NewInput(). - Title("Username"). - Value(®istryView.Username). - Validate(func(str string) error { - if str == "" { - return errors.New("username can not be blank") - } - return nil - }), - huh.NewInput(). - Title("Password"). - EchoMode(huh.EchoModePassword). - Value(®istryView.Password). - Validate(func(str string) error { - if str == "" { - return errors.New("password can not be blank") - } - return nil - }), - ), - ).WithTheme(views.GetCustomTheme()) - - err := form.Run() - if err != nil { - log.Fatal(err) - } - - if err != nil { - log.Fatal(err) - } -} diff --git a/pkg/views/env/delete.go b/pkg/views/env/delete.go new file mode 100644 index 0000000000..76a6f37671 --- /dev/null +++ b/pkg/views/env/delete.go @@ -0,0 +1,23 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package env + +import ( + "context" + + apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" + "github.com/daytonaio/daytona/pkg/apiclient" + "github.com/daytonaio/daytona/pkg/views/env/selection" +) + +func DeleteEnvVarsView(ctx context.Context, apiClient apiclient.APIClient) ([]*apiclient.EnvironmentVariable, error) { + envVars, res, err := apiClient.EnvVarAPI.ListEnvironmentVariables(ctx).Execute() + if err != nil { + return nil, apiclient_util.HandleErrorResponse(res, err) + } + + selectedEnvVars := selection.GetEnvironmentVariablesFromPrompt(envVars, "Delete") + + return selectedEnvVars, nil +} diff --git a/pkg/views/env/form/model.go b/pkg/views/env/form/model.go new file mode 100644 index 0000000000..611eadc6dd --- /dev/null +++ b/pkg/views/env/form/model.go @@ -0,0 +1,126 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package form + +import ( + "fmt" + + tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/huh" + "github.com/charmbracelet/lipgloss" + "github.com/daytonaio/daytona/pkg/views" +) + +const maxWidth = 160 + +var userCancelled bool + +type styles struct { + HeaderText, FooterText lipgloss.Style +} + +func newStyles(lg *lipgloss.Renderer) *styles { + s := styles{} + s.HeaderText = lg.NewStyle(). + Foreground(views.Green). + Bold(true). + Padding(1, 1, 0, 0) + s.FooterText = lg.NewStyle(). + Foreground(views.Gray). + Bold(true). + Padding(1, 1, 0, 0) + return &s +} + +type formModel struct { + lg *lipgloss.Renderer + styles *styles + form *huh.Form + width int + quitting bool + tip string +} + +func NewFormModel(key, value *string) formModel { + m := formModel{width: maxWidth} + m.lg = lipgloss.DefaultRenderer() + m.styles = newStyles(m.lg) + + m.form = huh.NewForm( + huh.NewGroup( + huh.NewInput(). + Title("Key"). + Value(key). + Validate(func(s string) error { + if s == "" { + return fmt.Errorf("key cannot be empty") + } + return nil + }), + huh.NewInput(). + Title("Value"). + Value(value). + Validate(func(s string) error { + if s == "" { + return fmt.Errorf("key cannot be empty") + } + return nil + }), + ), + ).WithTheme(views.GetCustomTheme()).WithHeight(12) + + m.tip = "\nTip: To set container registry credentials, add the following environment variables:\n <*>_CONTAINER_REGISTRY_SERVER\n <*>_CONTAINER_REGISTRY_USERNAME\n <*>_CONTAINER_REGISTRY_PASSWORD" + + return m +} + +func (m formModel) Init() tea.Cmd { + return m.form.Init() +} + +func (m formModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + switch msg := msg.(type) { + case tea.KeyMsg: + switch msg.String() { + case "ctrl+c": + m.quitting = true + userCancelled = true + return m, tea.Quit + case "f10": + m.quitting = true + m.form.State = huh.StateCompleted + return m, tea.Quit + } + } + + var cmds []tea.Cmd + + // Process the form + form, cmd := m.form.Update(msg) + if f, ok := form.(*huh.Form); ok { + m.form = f + cmds = append(cmds, cmd) + } + + if m.form.State == huh.StateCompleted { + // Quit when the form is done. + m.quitting = true + cmds = append(cmds, tea.Quit) + } + + return m, tea.Batch(cmds...) +} + +func (m formModel) View() string { + if m.quitting { + return "" + } + + view := m.styles.HeaderText.Render("Set server environment variable\n") + m.form.WithHeight(5).View() + m.styles.FooterText.Render(m.tip) + + return view +} +func IsUserCancelled() bool { + return userCancelled +} diff --git a/pkg/views/env/list.go b/pkg/views/env/list.go index 47bd314af0..20938b9144 100644 --- a/pkg/views/env/list.go +++ b/pkg/views/env/list.go @@ -8,6 +8,7 @@ import ( "os" "strings" + "github.com/daytonaio/daytona/pkg/apiclient" "github.com/daytonaio/daytona/pkg/views" "github.com/charmbracelet/lipgloss" @@ -34,7 +35,7 @@ func getRowData(key, value string) *RowData { return &RowData{key, value} } -func List(envVars map[string]string) { +func List(envVars []apiclient.EnvironmentVariable) { if len(envVars) == 0 { views_util.NotifyEmptyEnvVarList(true) return @@ -46,11 +47,11 @@ func List(envVars map[string]string) { data := [][]string{} - for k, v := range envVars { + for _, envVar := range envVars { var rowData *RowData var row []string - rowData = getRowData(k, v) + rowData = getRowData(envVar.Key, envVar.Value) if rowData == nil { continue } @@ -86,12 +87,12 @@ func List(envVars map[string]string) { fmt.Println(views.BaseTableStyle.Render(t.String())) } -func renderUnstyledList(envVars map[string]string) { +func renderUnstyledList(envVars []apiclient.EnvironmentVariable) { output := "\n" - for k, v := range envVars { - output += fmt.Sprintf("%s\t%s", views.GetPropertyKey("Key:"), k) + "\n" - output += fmt.Sprintf("%s\t%s", views.GetPropertyKey("Value:"), v) + "\n" + for _, envVar := range envVars { + output += fmt.Sprintf("%s\t%s", views.GetPropertyKey("Key:"), envVar.Key) + "\n" + output += fmt.Sprintf("%s\t%s", views.GetPropertyKey("Value:"), envVar.Value) + "\n" output += "\n\n" } diff --git a/pkg/views/env/selection/env.go b/pkg/views/env/selection/env.go new file mode 100644 index 0000000000..aa9eef528c --- /dev/null +++ b/pkg/views/env/selection/env.go @@ -0,0 +1,108 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package selection + +import ( + "fmt" + "os" + + "github.com/charmbracelet/bubbles/list" + tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/lipgloss" + "github.com/daytonaio/daytona/pkg/apiclient" + "github.com/daytonaio/daytona/pkg/views" +) + +func generateEnvVarsList(envVars []apiclient.EnvironmentVariable, isMultipleSelect bool, action string) []list.Item { + // Initialize an empty list of items. + items := []list.Item{} + + // Populate items with titles and descriptions from envVars. + for _, envVar := range envVars { + newItem := item[apiclient.EnvironmentVariable]{ + key: envVar.Key, + desc: envVar.Value, + envVar: &envVar, + choiceProperty: envVar, + } + + if isMultipleSelect { + newItem.isMultipleSelect = true + newItem.action = action + } + + items = append(items, newItem) + } + + return items +} + +func getEnvVarsProgramEssentials(modelTitle string, actionVerb string, envVars []apiclient.EnvironmentVariable, footerText string, isMultipleSelect bool) tea.Model { + + items := generateEnvVarsList(envVars, isMultipleSelect, actionVerb) + + d := ItemDelegate[apiclient.EnvironmentVariable]{} + + l := list.New(items, d, 0, 0) + + l.Styles.FilterPrompt = lipgloss.NewStyle().Foreground(views.Green) + l.Styles.FilterCursor = lipgloss.NewStyle().Foreground(views.Green) + + l.FilterInput.PromptStyle = lipgloss.NewStyle().Foreground(views.Green) + l.FilterInput.TextStyle = lipgloss.NewStyle().Foreground(views.Green) + + m := model[apiclient.EnvironmentVariable]{list: l} + + m.list.Title = views.GetStyledMainTitle(modelTitle + actionVerb) + m.list.Styles.Title = lipgloss.NewStyle().Foreground(views.Green).Bold(true) + m.footer = footerText + + p, err := tea.NewProgram(m, tea.WithAltScreen()).Run() + + if err != nil { + fmt.Println("Error running program:", err) + os.Exit(1) + } + + return p +} + +func selectEnvironmentVariablePrompt(envVars []apiclient.EnvironmentVariable, actionVerb string, choiceChan chan<- *apiclient.EnvironmentVariable) { + p := getEnvVarsProgramEssentials("Select an Environment Variable To ", actionVerb, envVars, "", false) + if m, ok := p.(model[apiclient.EnvironmentVariable]); ok && m.choice != nil { + choiceChan <- m.choice + } else { + choiceChan <- nil + } +} + +func GetEnvironmentVariableFromPrompt(envVars []apiclient.EnvironmentVariable, actionVerb string) *apiclient.EnvironmentVariable { + choiceChan := make(chan *apiclient.EnvironmentVariable) + + go selectEnvironmentVariablePrompt(envVars, actionVerb, choiceChan) + + return <-choiceChan +} + +func selectEnvironmentVariablesFromPrompt(envVars []apiclient.EnvironmentVariable, actionVerb string, choiceChan chan<- []*apiclient.EnvironmentVariable) { + footerText := lipgloss.NewStyle().Bold(true).PaddingLeft(2).Render(fmt.Sprintf("\n\nPress 'x' to mark a server environment variable.\nPress 'enter' to %s the current/marked server environment variables.", actionVerb)) + p := getEnvVarsProgramEssentials("Select Server Environment Variables To ", actionVerb, envVars, footerText, true) + + m, ok := p.(model[apiclient.EnvironmentVariable]) + if ok && m.choices != nil { + choiceChan <- m.choices + } else if ok && m.choice != nil { + choiceChan <- []*apiclient.EnvironmentVariable{m.choice} + } else { + choiceChan <- nil + } +} + +func GetEnvironmentVariablesFromPrompt(envVars []apiclient.EnvironmentVariable, actionVerb string) []*apiclient.EnvironmentVariable { + choiceChan := make(chan []*apiclient.EnvironmentVariable) + + go selectEnvironmentVariablesFromPrompt(envVars, actionVerb, choiceChan) + + return <-choiceChan +} diff --git a/pkg/views/env/selection/view.go b/pkg/views/env/selection/view.go new file mode 100644 index 0000000000..88d71ceb49 --- /dev/null +++ b/pkg/views/env/selection/view.go @@ -0,0 +1,203 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package selection + +import ( + "fmt" + "io" + "log" + "os" + "strings" + "time" + + "github.com/charmbracelet/bubbles/list" + tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/lipgloss" + "github.com/daytonaio/daytona/cmd/daytona/config" + "github.com/daytonaio/daytona/pkg/apiclient" + "github.com/daytonaio/daytona/pkg/views" + "golang.org/x/term" +) + +var selectedStyles = lipgloss.NewStyle(). + Border(lipgloss.NormalBorder(), false, false, false, true). + BorderForeground(views.Green). + Bold(true). + Padding(0, 0, 0, 1) + +var statusMessageGreenStyle = lipgloss.NewStyle().Bold(true). + Foreground(lipgloss.AdaptiveColor{Light: "#04B575", Dark: "#04B575"}). + Render + +var statusMessageDangerStyle = lipgloss.NewStyle().Bold(true). + Foreground(lipgloss.AdaptiveColor{Light: "#FF474C", Dark: "#FF474C"}). + Render + +type item[T any] struct { + key, desc string + envVar *apiclient.EnvironmentVariable + choiceProperty T + isMarked bool + isMultipleSelect bool + action string +} + +func (i item[T]) Key() string { return i.key } +func (i item[T]) Description() string { return i.desc } +func (i item[T]) FilterValue() string { return i.key } + +type model[T any] struct { + list list.Model + choice *T + choices []*T + footer string + initialWidthSet bool +} + +func (m model[T]) Init() tea.Cmd { + return nil +} + +func (m model[T]) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + if !m.initialWidthSet { + _, _, err := term.GetSize(int(os.Stdout.Fd())) + if err != nil { + m.list.SetWidth(150) + } + } + + switch msg := msg.(type) { + case tea.KeyMsg: + switch keypress := msg.String(); keypress { + case "ctrl+c": + return m, tea.Quit + + case "enter": + i, ok := m.list.SelectedItem().(item[T]) + if ok { + m.choice = &i.choiceProperty + } + envVarList := m.list.Items() + var choices []*T + for _, envVar := range envVarList { + if envVar.(item[T]).isMarked { + envVarItem, ok := envVar.(item[T]) + if !ok { + continue + } + choices = append(choices, &envVarItem.choiceProperty) + } + + } + m.choices = choices + return m, tea.Quit + } + + case tea.WindowSizeMsg: + h, v := views.DocStyle.GetFrameSize() + m.list.SetSize(msg.Width-h, msg.Height-v) + } + + var cmd tea.Cmd + m.list, cmd = m.list.Update(msg) + return m, cmd +} + +func (m model[T]) View() string { + if m.footer == "" { + c, err := config.GetConfig() + if err != nil { + log.Fatal(err) + } + + activeProfile, err := c.GetActiveProfile() + if err != nil { + log.Fatal(err) + } + + m.footer = views.GetListFooter(activeProfile.Name, views.DefaultListFooterPadding) + } + + terminalWidth, terminalHeight, err := term.GetSize(int(os.Stdout.Fd())) + if err != nil { + return "" + } + + if m.list.FilterState() == list.Filtering { + return views.DocStyle.MaxWidth(terminalWidth - 4).MaxHeight(terminalHeight - 4).Render(m.list.View() + m.footer) + } + + return views.DocStyle.MaxWidth(terminalWidth - 4).Height(terminalHeight - 2).Render(m.list.View() + m.footer) +} + +type ItemDelegate[T any] struct { +} + +func (d ItemDelegate[T]) Render(w io.Writer, m list.Model, index int, listItem list.Item) { + i, _ := listItem.(item[T]) // Cast the listItem to your custom item type + s := strings.Builder{} + + var isSelected = index == m.Index() + + baseStyles := lipgloss.NewStyle().Padding(0, 0, 0, 2) + + key := baseStyles.Render(i.Key()) + description := baseStyles.Render(i.Description()) + + // Adjust styles as the user moves through the menu + if isSelected { + key = selectedStyles.Foreground(views.Green).Render(i.Key()) + description = selectedStyles.Foreground(views.DimmedGreen).Render(i.Description()) + } + + // Render to the terminal + s.WriteString(lipgloss.JoinHorizontal(lipgloss.Bottom, key)) + s.WriteRune('\n') + s.WriteString(description) + s.WriteRune('\n') + + fmt.Fprint(w, s.String()) +} + +func (d ItemDelegate[T]) Height() int { + height := lipgloss.NewStyle().GetVerticalFrameSize() + 4 + return height +} + +func (d ItemDelegate[T]) Spacing() int { + return 0 +} + +func (d ItemDelegate[T]) Update(msg tea.Msg, m *list.Model) tea.Cmd { + i, ok := m.SelectedItem().(item[T]) + if !ok { + return nil + } + + m.StatusMessageLifetime = time.Millisecond * 2000 + + var title string + switch msg := msg.(type) { + case tea.KeyMsg: + switch keypress := msg.String(); keypress { + case "x": + if !i.isMultipleSelect { + return nil + } + if i.isMarked { + i.key = strings.TrimPrefix(i.key, statusMessageDangerStyle(fmt.Sprintf("%s: ", i.action))) + i.isMarked = false + m.SetItem(m.Index(), i) + return m.NewStatusMessage(statusMessageGreenStyle("Removed environment variable from list: ") + statusMessageGreenStyle(i.key)) + } + + title = i.key + i.key = statusMessageDangerStyle(fmt.Sprintf("%s: ", i.action)) + statusMessageGreenStyle(i.key) + i.isMarked = true + m.SetItem(m.Index(), i) + return m.NewStatusMessage(statusMessageDangerStyle("Added envrionment variable to list: ") + statusMessageGreenStyle(title)) + } + } + return nil +} diff --git a/pkg/views/env/set.go b/pkg/views/env/set.go new file mode 100644 index 0000000000..638770244b --- /dev/null +++ b/pkg/views/env/set.go @@ -0,0 +1,54 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package env + +import ( + "fmt" + + tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/huh" + "github.com/daytonaio/daytona/pkg/views" + "github.com/daytonaio/daytona/pkg/views/env/form" +) + +func SetEnvVarsView(envVarsMap *map[string]string) error { + return runSetEnvVarsForm(envVarsMap) +} + +func runSetEnvVarsForm(envVarsMap *map[string]string) error { + var key, value string + + m := form.NewFormModel(&key, &value) + + if _, err := tea.NewProgram(m, tea.WithAltScreen()).Run(); err != nil { + return err + } + + if form.IsUserCancelled() { + return fmt.Errorf("user cancelled") + } + + (*envVarsMap)[key] = value + + var addAntoher bool + + form := huh.NewForm( + huh.NewGroup( + huh.NewConfirm(). + Title("Add another environment variable?"). + Value(&addAntoher), + ), + ).WithTheme(views.GetCustomTheme()).WithHeight(6) + + err := form.Run() + if err != nil { + return err + } + + if addAntoher { + return runSetEnvVarsForm(envVarsMap) + } + + return nil +} diff --git a/pkg/views/ide/code.go b/pkg/views/ide/code.go index f3a2a42643..891f3465dc 100644 --- a/pkg/views/ide/code.go +++ b/pkg/views/ide/code.go @@ -10,7 +10,7 @@ import ( "github.com/daytonaio/daytona/pkg/views" ) -func RenderIdeOpeningMessage(workspaceId, projectName, ideId string, ideList []config.Ide) { +func RenderIdeOpeningMessage(target, workspaceName, ideId string, ideList []config.Ide) { ideName := "" for _, ide := range ideList { if ide.Id == ideId { @@ -18,5 +18,5 @@ func RenderIdeOpeningMessage(workspaceId, projectName, ideId string, ideList []c break } } - views.RenderInfoMessage(fmt.Sprintf("Opening the project '%s' from workspace '%s' in %s", projectName, workspaceId, ideName)) + views.RenderInfoMessage(fmt.Sprintf("Opening workspace '%s' from target '%s' in %s", workspaceName, target, ideName)) } diff --git a/pkg/views/ide/start_workspace.go b/pkg/views/ide/start.go similarity index 65% rename from pkg/views/ide/start_workspace.go rename to pkg/views/ide/start.go index 92d56004f7..e8722fef0b 100644 --- a/pkg/views/ide/start_workspace.go +++ b/pkg/views/ide/start.go @@ -12,12 +12,20 @@ import ( ) func RunStartWorkspaceForm(workspaceName string) bool { + return runStartForm("workspace", workspaceName) +} + +func RunStartTargetForm(targetName string) bool { + return runStartForm("target", targetName) +} + +func runStartForm(resource, name string) bool { confirmCheck := true form := huh.NewForm( huh.NewGroup( huh.NewConfirm(). - Title(fmt.Sprintf("The workspace %s is stopped, would you like to start it?", workspaceName)). + Title(fmt.Sprintf("The %s %s is stopped, would you like to start it?", resource, name)). Value(&confirmCheck), ), ).WithTheme(views.GetCustomTheme()) diff --git a/pkg/views/initial/view.go b/pkg/views/initial/view.go index e05b796de9..020d7996b6 100644 --- a/pkg/views/initial/view.go +++ b/pkg/views/initial/view.go @@ -68,8 +68,8 @@ var commandViews []CommandView = []CommandView{ {Command: "server", Name: "daytona server", Desc: "(start the Daytona Server daemon)"}, {Command: "create", Name: "daytona create", Desc: "(create a new workspace)"}, {Command: "code", Name: "daytona code", Desc: "(open a workspace in your preferred IDE)"}, - {Command: "git-provider add", Name: "daytona git-provider add", Desc: "(register a Git provider account)"}, - {Command: "target set", Name: "daytona target set", Desc: "(run workspaces on a remote machine)"}, + {Command: "git-provider create", Name: "daytona git-provider create", Desc: "(register a Git provider account)"}, + {Command: "target-config create", Name: "daytona target-config create", Desc: "(run workspaces on a remote machine)"}, {Command: "docs", Name: "daytona docs", Desc: "(open Daytona docs in default browser)\n"}, {Command: "help", Name: "view all commands", Desc: ""}, } diff --git a/pkg/views/logs/display.go b/pkg/views/logs/display.go index 13f6c43bb1..894d0fea27 100644 --- a/pkg/views/logs/display.go +++ b/pkg/views/logs/display.go @@ -5,6 +5,8 @@ package logs import ( "fmt" + "io" + "slices" "strings" "github.com/charmbracelet/lipgloss" @@ -12,15 +14,25 @@ import ( "github.com/daytonaio/daytona/pkg/views" ) -var FIRST_PROJECT_INDEX = 0 -var STATIC_INDEX = -1 -var WORKSPACE_PREFIX = "WORKSPACE" -var PROVIDER_PREFIX = "PROVIDER" +const FIRST_WORKSPACE_INDEX = 0 +const STATIC_INDEX = -1 -var longestPrefixLength = len(WORKSPACE_PREFIX) -var maxPrefixLength = 20 -var prefixDelimiter = " | " -var prefixPadding = " " +var minimumLongestPrefixLength = 4 + +const maxPrefixLength = 20 +const prefixDelimiter = " | " +const prefixPadding = " " + +func DisplayLogsFromReader(reader io.Reader) { + for { + buf := make([]byte, 1024) + n, err := reader.Read(buf) + if err != nil { + break + } + fmt.Print(string(buf[:n])) + } +} func DisplayLogs(logEntriesChan <-chan logs.LogEntry, index int) { for logEntry := range logEntriesChan { @@ -32,38 +44,21 @@ func DisplayLogEntry(logEntry logs.LogEntry, index int) { line := logEntry.Msg prefixColor := getPrefixColor(index, logEntry.Source) - var prefixText string + prefixText := logEntry.Label - if logEntry.ProjectName != nil { - prefixText = *logEntry.ProjectName - } - - if logEntry.BuildId != nil { - prefixText = *logEntry.BuildId - } - - if index == STATIC_INDEX { - if logEntry.Source == string(logs.LogSourceProvider) { - prefixText = PROVIDER_PREFIX - } else { - prefixText = WORKSPACE_PREFIX - } + if prefixText == "" { + prefixText = strings.ToUpper(logEntry.Source) } prefix := lipgloss.NewStyle().Foreground(prefixColor).Bold(true).Render(formatPrefixText(prefixText)) if index == STATIC_INDEX { - if logEntry.Source == string(logs.LogSourceProvider) { - line = fmt.Sprintf("%s%s\033[1m%s\033[0m", prefixPadding, prefix, line) - } else { - line = fmt.Sprintf("%s%s%s \033[1m%s\033[0m", prefixPadding, prefix, views.CheckmarkSymbol, line) - } - fmt.Print(line) + fmt.Printf("%s%s\033[1m%s\033[0m", prefixPadding, prefix, line) return } // Ensure the cursor moving never overwrites the prefix - cursorOffset := longestPrefixLength + len(prefixDelimiter) + 2*len(prefixPadding) + cursorOffset := minimumLongestPrefixLength + len(prefixDelimiter) + 2*len(prefixPadding) line = strings.ReplaceAll(line, "\r", fmt.Sprintf("\u001b[%dG", cursorOffset)) line = strings.ReplaceAll(line, "\u001b[0G", fmt.Sprintf("\u001b[%dG", cursorOffset)) @@ -88,19 +83,17 @@ func DisplayLogEntry(logEntry logs.LogEntry, index int) { fmt.Print(result) } -func CalculateLongestPrefixLength(projectNames []string) { - for _, projectName := range projectNames { - if len(projectName) > longestPrefixLength { - longestPrefixLength = len(projectName) - } - } +func SetupLongestPrefixLength(workspaceNames []string) { + minimumLongestPrefixLength = len(slices.MaxFunc(workspaceNames, func(a, b string) int { + return len(a) - len(b) + })) } func formatPrefixText(input string) string { - prefixLength := longestPrefixLength + prefixLength := minimumLongestPrefixLength if prefixLength > maxPrefixLength { prefixLength = maxPrefixLength - longestPrefixLength = maxPrefixLength + minimumLongestPrefixLength = maxPrefixLength } // Trim input if longer than maxPrefixLength diff --git a/pkg/views/prebuild/add/add.go b/pkg/views/prebuild/create/create.go similarity index 93% rename from pkg/views/prebuild/add/add.go rename to pkg/views/prebuild/create/create.go index 950c0862ef..daaf0e579d 100644 --- a/pkg/views/prebuild/add/add.go +++ b/pkg/views/prebuild/create/create.go @@ -1,7 +1,7 @@ // Copyright 2024 Daytona Platforms Inc. // SPDX-License-Identifier: Apache-2.0 -package add +package create import ( "errors" @@ -19,12 +19,12 @@ var DEFAULT_COMMIT_INTERVAL = "10" var DEFAULT_RETENTION = "3" type PrebuildAddView struct { - ProjectConfigName string - Branch string - CommitInterval string - TriggerFiles []string - Retention string - RunBuildOnAdd bool + WorkspaceTemplateName string + Branch string + CommitInterval string + TriggerFiles []string + Retention string + RunBuildOnAdd bool } func PrebuildCreationView(prebuildAddView *PrebuildAddView, editing bool) { diff --git a/pkg/views/prebuild/info/view.go b/pkg/views/prebuild/info/view.go index 148c9eb7ed..9ff82f6dad 100644 --- a/pkg/views/prebuild/info/view.go +++ b/pkg/views/prebuild/info/view.go @@ -32,7 +32,7 @@ func Render(prebuild *apiclient.PrebuildDTO, forceUnstyled bool) { output += getInfoLine("ID", prebuild.Id) + "\n" - output += getInfoLine("Project config", prebuild.ProjectConfigName) + "\n" + output += getInfoLine("Workspace template", prebuild.WorkspaceTemplateName) + "\n" output += getInfoLine("Branch", views.GetBranchNameLabel(prebuild.Branch)) + "\n" diff --git a/pkg/views/prebuild/list/view.go b/pkg/views/prebuild/list/view.go index 3ff2f1a241..dbeebacaa2 100644 --- a/pkg/views/prebuild/list/view.go +++ b/pkg/views/prebuild/list/view.go @@ -17,11 +17,11 @@ import ( var maxTriggerFilesStringLength = 24 type rowData struct { - ProjectConfigName string - Branch string - CommitInterval string - TriggerFiles string - Retention string + WorkspaceTemplateName string + Branch string + CommitInterval string + TriggerFiles string + Retention string } func ListPrebuilds(prebuildList []apiclient.PrebuildDTO) { @@ -37,7 +37,7 @@ func ListPrebuilds(prebuildList []apiclient.PrebuildDTO) { } table := util.GetTableView(data, []string{ - "Project Config", "Branch", "Commit Interval", "Trigger files", "Build Retention", + "Workspace Template", "Branch", "Commit Interval", "Trigger files", "Build Retention", }, nil, func() { renderUnstyledList(prebuildList) }) @@ -46,10 +46,10 @@ func ListPrebuilds(prebuildList []apiclient.PrebuildDTO) { } func renderUnstyledList(prebuildList []apiclient.PrebuildDTO) { - for _, pc := range prebuildList { - info.Render(&pc, true) + for _, p := range prebuildList { + info.Render(&p, true) - if pc.Id != prebuildList[len(prebuildList)-1].Id { + if p.Id != prebuildList[len(prebuildList)-1].Id { fmt.Printf("\n%s\n\n", views.SeparatorString) } } @@ -58,7 +58,7 @@ func renderUnstyledList(prebuildList []apiclient.PrebuildDTO) { func getRowFromData(prebuildConfig apiclient.PrebuildDTO) []string { var data rowData - data.ProjectConfigName = prebuildConfig.ProjectConfigName + views_util.AdditionalPropertyPadding + data.WorkspaceTemplateName = prebuildConfig.WorkspaceTemplateName + views_util.AdditionalPropertyPadding data.Branch = prebuildConfig.Branch if prebuildConfig.CommitInterval != nil { data.CommitInterval = strconv.Itoa(int(*prebuildConfig.CommitInterval)) @@ -69,7 +69,7 @@ func getRowFromData(prebuildConfig apiclient.PrebuildDTO) []string { data.Retention = strconv.Itoa(int(prebuildConfig.Retention)) return []string{ - views.NameStyle.Render(data.ProjectConfigName), + views.NameStyle.Render(data.WorkspaceTemplateName), views.DefaultRowDataStyle.Render(views.GetBranchNameLabel(data.Branch)), views.ActiveStyle.Render(data.CommitInterval), views.DefaultRowDataStyle.Render(data.TriggerFiles), diff --git a/pkg/views/profile/create.go b/pkg/views/profile/create.go index 2839f1b461..f56204ab29 100644 --- a/pkg/views/profile/create.go +++ b/pkg/views/profile/create.go @@ -51,7 +51,7 @@ func ProfileCreationView(c *config.Config, profileAddView *ProfileAddView, editi nameInput, huh.NewInput(). Title("Server API URL"). - Description("If you want to connect to a remote Daytona Server, start by running 'daytona api-key new' on the remote machine"). + Description("If you want to connect to a remote Daytona Server, start by running 'daytona api-key create' on the remote machine"). Value(&profileAddView.ApiUrl). Validate(func(str string) error { if str == "" { diff --git a/pkg/views/projectconfig/list/view.go b/pkg/views/projectconfig/list/view.go deleted file mode 100644 index b87b0d10dd..0000000000 --- a/pkg/views/projectconfig/list/view.go +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package list - -import ( - "fmt" - - "github.com/daytonaio/daytona/internal/util" - "github.com/daytonaio/daytona/pkg/apiclient" - "github.com/daytonaio/daytona/pkg/views" - "github.com/daytonaio/daytona/pkg/views/projectconfig/info" - views_util "github.com/daytonaio/daytona/pkg/views/util" -) - -type rowData struct { - Name string - Repository string - Build string - Prebuilds string - IsDefault string -} - -func ListProjectConfigs(projectConfigList []apiclient.ProjectConfig, apiServerConfig *apiclient.ServerConfig, specifyGitProviders bool) { - if len(projectConfigList) == 0 { - views_util.NotifyEmptyProjectConfigList(true) - return - } - - data := [][]string{} - - for _, pc := range projectConfigList { - data = append(data, getRowFromData(pc, apiServerConfig, specifyGitProviders)) - } - - table := views_util.GetTableView(data, []string{ - "Name", "Repository", "Build", "Prebuild rules", "Default", - }, nil, func() { - renderUnstyledList(projectConfigList, apiServerConfig) - }) - - fmt.Println(table) -} - -func renderUnstyledList(projectConfigList []apiclient.ProjectConfig, apiServerConfig *apiclient.ServerConfig) { - for _, pc := range projectConfigList { - info.Render(&pc, apiServerConfig, true) - - if pc.Name != projectConfigList[len(projectConfigList)-1].Name { - fmt.Printf("\n%s\n\n", views.SeparatorString) - } - } -} - -func getRowFromData(projectConfig apiclient.ProjectConfig, apiServerConfig *apiclient.ServerConfig, specifyGitProviders bool) []string { - var isDefault string - var data rowData - - data.Name = projectConfig.Name + views_util.AdditionalPropertyPadding - data.Repository = util.GetRepositorySlugFromUrl(projectConfig.RepositoryUrl, specifyGitProviders) - data.Prebuilds = "None" - - projectDefaults := &views_util.ProjectConfigDefaults{ - Image: &apiServerConfig.DefaultProjectImage, - ImageUser: &apiServerConfig.DefaultProjectUser, - } - - createProjectDto := apiclient.CreateProjectDTO{ - BuildConfig: projectConfig.BuildConfig, - } - - _, data.Build = views_util.GetProjectBuildChoice(createProjectDto, projectDefaults) - - if projectConfig.Default { - isDefault = views.ActiveStyle.Render("Yes") - } else { - isDefault = views.InactiveStyle.Render("/") - } - - if len(projectConfig.Prebuilds) > 0 { - data.Prebuilds = fmt.Sprintf("%d", len(projectConfig.Prebuilds)) - } - - return []string{ - views.NameStyle.Render(data.Name), - views.DefaultRowDataStyle.Render(data.Repository), - views.DefaultRowDataStyle.Render(data.Build), - views.DefaultRowDataStyle.Render(data.Prebuilds), - isDefault, - } -} diff --git a/pkg/views/provider/install/list.go b/pkg/views/provider/install/list.go new file mode 100644 index 0000000000..0171273138 --- /dev/null +++ b/pkg/views/provider/install/list.go @@ -0,0 +1,75 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package install + +import ( + "fmt" + + "github.com/daytonaio/daytona/pkg/apiclient" + "github.com/daytonaio/daytona/pkg/views" + "github.com/daytonaio/daytona/pkg/views/util" +) + +type rowData struct { + Label string + Name string + Version string +} + +func List(providerList []apiclient.ProviderDTO) { + if len(providerList) == 0 { + util.NotifyEmptyProviderList(true) + return + } + + data := [][]string{} + + for _, provider := range providerList { + data = append(data, getRowFromData(&provider)) + } + + table := util.GetTableView(data, []string{ + "Provider", "Runner", "Name", "Version", + }, nil, func() { + renderUnstyledList(providerList) + }) + + fmt.Println(table) +} + +func getRowFromData(provider *apiclient.ProviderDTO) []string { + var data rowData + + if provider.Label != nil { + data.Label = *provider.Label + } else { + data.Label = provider.Name + } + data.Name = provider.Name + data.Version = provider.Version + + return []string{ + views.NameStyle.Render(data.Label), + views.DefaultRowDataStyle.Render(data.Name), + views.DefaultRowDataStyle.Render(data.Version), + } +} + +func renderUnstyledList(providerList []apiclient.ProviderDTO) { + output := "\n" + + for _, provider := range providerList { + if provider.Label != nil { + output += fmt.Sprintf("%s %s", views.GetPropertyKey("Provider: "), *provider.Label) + "\n\n" + } + output += fmt.Sprintf("%s %s", views.GetPropertyKey("Name: "), provider.Name) + "\n\n" + output += fmt.Sprintf("%s %s", views.GetPropertyKey("Version: "), provider.Version) + "\n" + + if provider.Name != providerList[len(providerList)-1].Name { + output += views.SeparatorString + "\n\n" + } + } + + fmt.Println(output) +} diff --git a/pkg/views/provider/install/select.go b/pkg/views/provider/install/select.go new file mode 100644 index 0000000000..72f6bdb70f --- /dev/null +++ b/pkg/views/provider/install/select.go @@ -0,0 +1,78 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package install + +import ( + "sort" + + "github.com/charmbracelet/bubbles/list" + tea "github.com/charmbracelet/bubbletea" + "github.com/daytonaio/daytona/pkg/apiclient" + "github.com/daytonaio/daytona/pkg/common" + "github.com/daytonaio/daytona/pkg/views" +) + +type ProviderInstallView struct { + Name string + Label *string + Version string +} + +var NewProviderId = "+ New Provider" + +func GetProviderFromInstallPrompt(providers []ProviderInstallView, title string, withNewProvider bool) (*ProviderInstallView, error) { + sortProvidersForInstall(providers) + + var items []list.Item + + for _, p := range providers { + items = append(items, item{ + provider: p, + }) + } + + if withNewProvider { + name := NewProviderId + items = append(items, item{ + provider: ProviderInstallView{ + Name: name, + }, + }) + } + + l := views.GetStyledSelectList(items) + m := model{list: l} + m.list.Title = views.GetStyledMainTitle(title) + + p, err := tea.NewProgram(m, tea.WithAltScreen()).Run() + if err != nil { + return nil, err + } + + if m, ok := p.(model); ok && m.choice != nil { + return m.choice, nil + } + + return nil, common.ErrCtrlCAbort +} + +func ProviderInstallListToView(providers []apiclient.ProviderDTO) []ProviderInstallView { + var providerViews []ProviderInstallView + + for _, p := range providers { + providerViews = append(providerViews, ProviderInstallView{ + Name: p.Name, + Label: p.Label, + Version: p.Version, + }) + } + + return providerViews +} + +func sortProvidersForInstall(providers []ProviderInstallView) { + sort.Slice(providers, func(i, j int) bool { + return (providers)[i].Name > (providers)[j].Name + }) +} diff --git a/pkg/views/target/view.go b/pkg/views/provider/install/view.go similarity index 71% rename from pkg/views/target/view.go rename to pkg/views/provider/install/view.go index d63112ef3b..fef6292038 100644 --- a/pkg/views/target/view.go +++ b/pkg/views/provider/install/view.go @@ -1,7 +1,7 @@ // Copyright 2024 Daytona Platforms Inc. // SPDX-License-Identifier: Apache-2.0 -package target +package install import ( "os" @@ -13,34 +13,32 @@ import ( ) type item struct { - target TargetView + provider ProviderInstallView } func (i item) Title() string { - title := i.target.Name - - if i.target.IsDefault { - title += " (default)" + title := i.provider.Name + if i.provider.Label != nil { + title = *i.provider.Label } return title } + func (i item) Description() string { - desc := i.target.ProviderInfo.Name - if i.target.ProviderInfo.Installed != nil { - if !*i.target.ProviderInfo.Installed { - desc += " (needs installing)" - } + return i.provider.Version +} +func (i item) FilterValue() string { + if i.provider.Label != nil { + return *i.provider.Label + } else { + return i.provider.Name } - - return desc } -func (i item) FilterValue() string { return i.target.Name } type model struct { list list.Model - choice *TargetView - footer string + choice *ProviderInstallView } func (m model) Init() tea.Cmd { @@ -57,7 +55,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { case "enter": i, ok := m.list.SelectedItem().(item) if ok { - m.choice = &i.target + m.choice = &i.provider } return m, tea.Quit } @@ -77,5 +75,5 @@ func (m model) View() string { return "" } - return views.DocStyle.Width(terminalWidth - 4).Height(terminalHeight - 4).Render(m.list.View() + m.footer) + return views.DocStyle.Width(terminalWidth - 4).Height(terminalHeight - 4).Render(m.list.View()) } diff --git a/pkg/views/provider/list.go b/pkg/views/provider/list.go index 25de7e09d6..4fd0145ec1 100644 --- a/pkg/views/provider/list.go +++ b/pkg/views/provider/list.go @@ -9,18 +9,18 @@ import ( "github.com/daytonaio/daytona/pkg/apiclient" "github.com/daytonaio/daytona/pkg/views" "github.com/daytonaio/daytona/pkg/views/util" - views_util "github.com/daytonaio/daytona/pkg/views/util" ) type rowData struct { - Label string - Name string - Version string + Label string + RunnerName string + Name string + Version string } -func List(providerList []apiclient.Provider) { +func List(providerList []apiclient.ProviderInfo) { if len(providerList) == 0 { - views_util.NotifyEmptyProviderList(true) + util.NotifyEmptyProviderList(true) return } @@ -31,7 +31,7 @@ func List(providerList []apiclient.Provider) { } table := util.GetTableView(data, []string{ - "Provider", "Name", "Version", + "Provider", "Runner", "Name", "Version", }, nil, func() { renderUnstyledList(providerList) }) @@ -39,7 +39,7 @@ func List(providerList []apiclient.Provider) { fmt.Println(table) } -func getRowFromData(provider *apiclient.Provider) []string { +func getRowFromData(provider *apiclient.ProviderInfo) []string { var data rowData if provider.Label != nil { @@ -47,23 +47,26 @@ func getRowFromData(provider *apiclient.Provider) []string { } else { data.Label = provider.Name } + data.RunnerName = provider.RunnerName data.Name = provider.Name data.Version = provider.Version return []string{ views.NameStyle.Render(data.Label), + views.DefaultRowDataStyle.Render(data.RunnerName), views.DefaultRowDataStyle.Render(data.Name), views.DefaultRowDataStyle.Render(data.Version), } } -func renderUnstyledList(providerList []apiclient.Provider) { +func renderUnstyledList(providerList []apiclient.ProviderInfo) { output := "\n" for _, provider := range providerList { if provider.Label != nil { output += fmt.Sprintf("%s %s", views.GetPropertyKey("Provider: "), *provider.Label) + "\n\n" } + output += fmt.Sprintf("%s %s", views.GetPropertyKey("Runner: "), provider.RunnerName) + "\n\n" output += fmt.Sprintf("%s %s", views.GetPropertyKey("Name: "), provider.Name) + "\n\n" output += fmt.Sprintf("%s %s", views.GetPropertyKey("Version: "), provider.Version) + "\n" diff --git a/pkg/views/provider/select.go b/pkg/views/provider/select.go index c1d2cb054f..72c0b8d21b 100644 --- a/pkg/views/provider/select.go +++ b/pkg/views/provider/select.go @@ -14,10 +14,14 @@ import ( ) type ProviderView struct { - Name string - Label *string - Version string - Installed *bool + Name string + AgentlessTarget *bool + Label *string + Version string + Installed *bool + RunnerName string + RunnerId string + TargetConfigManifest map[string]apiclient.TargetConfigProperty } var NewProviderId = "+ New Provider" @@ -58,15 +62,19 @@ func GetProviderFromPrompt(providers []ProviderView, title string, withNewProvid return nil, common.ErrCtrlCAbort } -func ProviderListToView(providers []apiclient.Provider) []ProviderView { +func ProviderListToView(providers []apiclient.ProviderInfo) []ProviderView { var providerViews []ProviderView for _, p := range providers { providerViews = append(providerViews, ProviderView{ - Name: p.Name, - Label: p.Label, - Version: p.Version, - Installed: nil, + Name: p.Name, + AgentlessTarget: p.AgentlessTarget, + Label: p.Label, + Version: p.Version, + Installed: nil, + RunnerId: p.RunnerId, + RunnerName: p.RunnerName, + TargetConfigManifest: p.TargetConfigManifest, }) } diff --git a/pkg/views/provider/view.go b/pkg/views/provider/view.go index ab7342ce82..2e0f7211dc 100644 --- a/pkg/views/provider/view.go +++ b/pkg/views/provider/view.go @@ -4,6 +4,7 @@ package provider import ( + "fmt" "os" "github.com/charmbracelet/bubbles/list" @@ -17,12 +18,18 @@ type item struct { } func (i item) Title() string { + title := i.provider.Name if i.provider.Label != nil { - return *i.provider.Label - } else { - return i.provider.Name + title = *i.provider.Label } + + if i.provider.RunnerName != "" { + title = fmt.Sprintf("%s (Runner %s)", title, i.provider.RunnerName) + } + + return title } + func (i item) Description() string { desc := i.provider.Version if i.provider.Installed != nil { diff --git a/pkg/views/purge/purge_resources.go b/pkg/views/purge/purge_resources.go new file mode 100644 index 0000000000..98d6640200 --- /dev/null +++ b/pkg/views/purge/purge_resources.go @@ -0,0 +1,52 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package purge + +import ( + "fmt" + "log" + "strings" + + "github.com/charmbracelet/huh" + "github.com/charmbracelet/lipgloss" + "github.com/daytonaio/daytona/pkg/views" +) + +func PurgeResourcesPrompt(continuePurge *bool, numOfTargets, numOfWorkspaces, numOfBuilds int) []string { + commands := []string{} + resources := []string{} + + if numOfBuilds > 0 { + resources = append(resources, fmt.Sprintf("builds: %d", numOfBuilds)) + commands = append(commands, lipgloss.NewStyle().Foreground(views.DimmedGreen).Render("daytona build delete -af")) + } + + if numOfWorkspaces > 0 { + resources = append(resources, fmt.Sprintf("workspaces: %d", numOfWorkspaces)) + commands = append(commands, lipgloss.NewStyle().Foreground(views.DimmedGreen).Render("daytona delete -afy")) + } + + if numOfTargets > 0 { + resources = append(resources, fmt.Sprintf("targets: %d", numOfTargets)) + commands = append(commands, lipgloss.NewStyle().Foreground(views.DimmedGreen).Render("daytona target delete -afy")) + } + + form := huh.NewForm( + huh.NewGroup( + huh.NewConfirm(). + Title(fmt.Sprintf("Leftover resources found: [%s]\nWould you like to continue with purge?", strings.Join(resources, ", "))). + Description("This action is irreversible."). + Affirmative("Continue"). + Negative("Abort"). + Value(continuePurge), + ), + ).WithTheme(views.GetCustomTheme()) + + err := form.Run() + if err != nil { + log.Fatal(err) + } + + return commands +} diff --git a/pkg/views/runner/config.go b/pkg/views/runner/config.go new file mode 100644 index 0000000000..92c059f037 --- /dev/null +++ b/pkg/views/runner/config.go @@ -0,0 +1,50 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package server + +import ( + "fmt" + + "github.com/charmbracelet/lipgloss" + "github.com/daytonaio/daytona/pkg/runner" + "github.com/daytonaio/daytona/pkg/views" +) + +func RenderConfig(config *runner.Config, showKey bool) { + output := views.GetStyledMainTitle("Daytona Runner Config") + "\n\n" + + output += fmt.Sprintf("%s %s", views.GetPropertyKey("Runner ID: "), config.Id) + "\n\n" + + output += fmt.Sprintf("%s %s", views.GetPropertyKey("Runner Name: "), config.Name) + "\n\n" + + output += fmt.Sprintf("%s %d", views.GetPropertyKey("Runner API Port: "), config.ApiPort) + "\n\n" + + output += fmt.Sprintf("%s %s", views.GetPropertyKey("Server API URL: "), config.ServerApiUrl) + "\n\n" + + if showKey { + output += fmt.Sprintf("%s %s", views.GetPropertyKey("Server API Key: "), config.ServerApiKey) + "\n\n" + } + + output += fmt.Sprintf("%s %s", views.GetPropertyKey("Providers Dir: "), config.ProvidersDir) + "\n\n" + + output += fmt.Sprintf("%s %s", views.GetPropertyKey("Log File Path: "), config.LogFile.Path) + "\n\n" + + output += fmt.Sprintf("%s %d", views.GetPropertyKey("Log File Max Size: "), config.LogFile.MaxSize) + "\n\n" + + output += fmt.Sprintf("%s %d", views.GetPropertyKey("Log File Max Backups: "), config.LogFile.MaxBackups) + "\n\n" + + output += fmt.Sprintf("%s %d", views.GetPropertyKey("Log File Max Age: "), config.LogFile.MaxAge) + "\n\n" + + output += fmt.Sprintf("%s %t", views.GetPropertyKey("Log File Local Time: "), config.LogFile.LocalTime) + "\n\n" + + output += fmt.Sprintf("%s %t", views.GetPropertyKey("Log File Compress: "), config.LogFile.Compress) + "\n\n" + + output += views.SeparatorString + "\n\n" + + output += fmt.Sprintf("To edit these values run: %s", lipgloss.NewStyle().Foreground(views.Green).Render("daytona runner configure")) + "\n\n" + + output += views.SeparatorString + + views.RenderContainerLayout(views.GetInfoMessage(output)) +} diff --git a/pkg/views/runner/configure.go b/pkg/views/runner/configure.go new file mode 100644 index 0000000000..6fdf33be51 --- /dev/null +++ b/pkg/views/runner/configure.go @@ -0,0 +1,193 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package server + +import ( + "errors" + "os" + "path/filepath" + "strconv" + + "github.com/charmbracelet/bubbles/help" + "github.com/charmbracelet/bubbles/key" + tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/huh" + "github.com/daytonaio/daytona/pkg/runner" + "github.com/daytonaio/daytona/pkg/views" + "github.com/daytonaio/daytona/pkg/views/util" +) + +type Model struct { + form *huh.Form + quitting bool + config *runner.Config + keymap keymap + help help.Model +} + +type keymap struct { + submit key.Binding +} + +func NewModel(config *runner.Config) Model { + m := Model{ + config: config, + help: help.New(), + keymap: keymap{ + submit: key.NewBinding(key.WithKeys("ctrl+s"), key.WithHelp("ctrl+s", "submit")), + }, + } + + m.form = m.createForm() + return m +} +func (m *Model) createForm() *huh.Form { + logFileMaxSize := strconv.Itoa(int(m.config.LogFile.MaxSize)) + logFileMaxBackups := strconv.Itoa(int(m.config.LogFile.MaxBackups)) + logFileMaxAge := strconv.Itoa(int(m.config.LogFile.MaxAge)) + apiPort := strconv.Itoa(int(m.config.ApiPort)) + + return huh.NewForm( + huh.NewGroup( + huh.NewInput(). + Title("ID"). + Description("Unique ID generated by the Daytona Server"). + Value(&m.config.Id), + huh.NewInput(). + Title("Name"). + Description("Unique name set on the Daytona Server"). + Value(&m.config.Name), + huh.NewInput(). + Title("Runner API Port"). + Description("Port used for exposing runner health-check endpoint"). + Value(&apiPort). + Validate(util.CreatePortValidator(&apiPort, &m.config.ApiPort)), + huh.NewInput(). + Title("Server API URL"). + Value(&m.config.ServerApiUrl), + huh.NewInput(). + Title("Server API Key"). + EchoMode(huh.EchoModePassword). + Value(&m.config.ServerApiKey), + huh.NewInput(). + Title("Providers Directory"). + Description("Directory will be created if it does not exist"). + Value(&m.config.ProvidersDir), + huh.NewConfirm(). + Title("Telemetry Enabled"). + Value(&m.config.TelemetryEnabled), + ), + huh.NewGroup( + huh.NewInput(). + Title("Log File Path"). + Description("File will be created if it does not exist"). + Value(&m.config.LogFile.Path). + Validate(func(s string) error { + _, err := os.Stat(s) + if os.IsNotExist(err) { + err = os.MkdirAll(filepath.Dir(s), 0755) + if err != nil { + return err + } + _, err = os.Create(s) + } + return err + }), + huh.NewInput(). + Title("Log File Max Size"). + Description("In megabytes"). + Value(&logFileMaxSize). + Validate(util.CreateIntValidator(&logFileMaxSize, &m.config.LogFile.MaxSize)), + huh.NewInput(). + Title("Log File Max Backups"). + Value(&logFileMaxBackups). + Validate(util.CreateIntValidator(&logFileMaxBackups, &m.config.LogFile.MaxBackups)), + huh.NewInput(). + Title("Log File Max Age"). + Description("In days"). + Value(&logFileMaxAge). + Validate(util.CreateIntValidator(&logFileMaxAge, &m.config.LogFile.MaxAge)), + huh.NewConfirm(). + Title("Log File Local Time"). + Description("Used for timestamping files. Default is UTC time."). + Value(&m.config.LogFile.LocalTime), + huh.NewConfirm(). + Title("Log File Compress"). + Value(&m.config.LogFile.Compress), + ), + ).WithTheme(views.GetCustomTheme()).WithHeight(20) +} + +func (m Model) Init() tea.Cmd { + return m.form.Init() +} + +func (m Model) ValidateField() { + // Validate the current field before submitting the form. + m.form.NextField() + m.form.PrevField() +} + +func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + + switch msg := msg.(type) { + case tea.KeyMsg: + switch msg.String() { + case "ctrl+s": + m.ValidateField() + if len(m.form.Errors()) > 0 { + return m, nil + } + m.quitting = true + return m, tea.Quit + case "ctrl+c": + m.config = nil + return m, tea.Quit + } + } + + var cmds []tea.Cmd + form, cmd := m.form.Update(msg) + if f, ok := form.(*huh.Form); ok { + m.form = f + cmds = append(cmds, cmd) + } + + if m.form.State == huh.StateCompleted { + m.quitting = true + return m, tea.Quit + } + + return m, tea.Batch(cmds...) +} + +func (m Model) View() string { + if m.quitting { + return "" + } + helpView := "" + if len(m.form.Errors()) == 0 { + helpView = views.DefaultRowDataStyle.Render(" • " + m.help.ShortHelpView([]key.Binding{m.keymap.submit})) + } + + // TODO: once huh is updated to properly focus fields, add alt screen titles + // return views.GetAltScreenTitle("SERVER CONFIGURATION") + m.form.View() + helpView + return m.form.View() + helpView +} + +func ConfigurationForm(config *runner.Config) (*runner.Config, error) { + m := NewModel(config) + + p, err := tea.NewProgram(m, tea.WithAltScreen()).Run() + + if err != nil { + return nil, err + } + + if m, ok := p.(Model); ok && m.config != nil { + return m.config, nil + } + + return nil, errors.New("no changes were made") +} diff --git a/pkg/views/workspace/selection/branch.go b/pkg/views/selection/branch.go similarity index 73% rename from pkg/views/workspace/selection/branch.go rename to pkg/views/selection/branch.go index 9186f08fb6..365233b130 100644 --- a/pkg/views/workspace/selection/branch.go +++ b/pkg/views/selection/branch.go @@ -14,10 +14,9 @@ import ( tea "github.com/charmbracelet/bubbletea" ) -func selectBranchPrompt(branches []apiclient.GitBranch, projectOrder int, selectionListOptions views.SelectionListOptions, choiceChan chan<- string, navChan chan<- string) { +func selectBranchPrompt(branches []apiclient.GitBranch, workspaceOrder int, selectionListOptions views.SelectionListOptions, choiceChan chan<- string, navChan chan<- string) { items := []list.Item{} - // Populate items with titles and descriptions from workspaces. for _, branch := range branches { newItem := item[string]{id: branch.Name, title: branch.Name, choiceProperty: branch.Name} if branch.Sha != "" { @@ -33,8 +32,8 @@ func selectBranchPrompt(branches []apiclient.GitBranch, projectOrder int, select l := views.GetStyledSelectList(items, selectionListOptions) title := "Choose a Branch" - if projectOrder > 1 { - title += fmt.Sprintf(" (Project #%d)", projectOrder) + if workspaceOrder > 1 { + title += fmt.Sprintf(" (Workspace #%d)", workspaceOrder) } l.Title = views.GetStyledMainTitle(title) l.Styles.Title = titleStyle @@ -59,11 +58,11 @@ func selectBranchPrompt(branches []apiclient.GitBranch, projectOrder int, select } } -func GetBranchFromPrompt(branches []apiclient.GitBranch, projectOrder int, selectionListOptions views.SelectionListOptions) (*apiclient.GitBranch, string) { +func GetBranchFromPrompt(branches []apiclient.GitBranch, workspaceOrder int, selectionListOptions views.SelectionListOptions) (*apiclient.GitBranch, string) { choiceChan := make(chan string) navChan := make(chan string) - go selectBranchPrompt(branches, projectOrder, selectionListOptions, choiceChan, navChan) + go selectBranchPrompt(branches, workspaceOrder, selectionListOptions, choiceChan, navChan) select { case branchName := <-choiceChan: diff --git a/pkg/views/workspace/selection/build.go b/pkg/views/selection/build.go similarity index 73% rename from pkg/views/workspace/selection/build.go rename to pkg/views/selection/build.go index 7cb7b382a8..af09f4bb57 100644 --- a/pkg/views/workspace/selection/build.go +++ b/pkg/views/selection/build.go @@ -17,19 +17,19 @@ import ( list_view "github.com/daytonaio/daytona/pkg/views/build/list" ) -func GetBuildFromPrompt(builds []apiclient.Build, actionVerb string) *apiclient.Build { - choiceChan := make(chan *apiclient.Build) +func GetBuildFromPrompt(builds []apiclient.BuildDTO, actionVerb string) *apiclient.BuildDTO { + choiceChan := make(chan *apiclient.BuildDTO) go selectBuildPrompt(builds, actionVerb, choiceChan) return <-choiceChan } -func selectBuildPrompt(builds []apiclient.Build, actionVerb string, choiceChan chan<- *apiclient.Build) { +func selectBuildPrompt(builds []apiclient.BuildDTO, actionVerb string, choiceChan chan<- *apiclient.BuildDTO) { list_view.SortBuilds(&builds) items := []list.Item{} for _, b := range builds { - newItem := item[apiclient.Build]{title: fmt.Sprintf("ID: %s (%s)", b.Id, b.State), desc: fmt.Sprintf("created %s", util.FormatTimestamp(b.CreatedAt)), choiceProperty: b} + newItem := item[apiclient.BuildDTO]{title: fmt.Sprintf("ID: %s - %s", b.Id, b.Repository.Url), desc: fmt.Sprintf("State: %s (created %s)", b.State.Name, util.FormatTimestamp(b.CreatedAt)), choiceProperty: b} items = append(items, newItem) } @@ -56,7 +56,7 @@ func selectBuildPrompt(builds []apiclient.Build, actionVerb string, choiceChan c l.Title = views.GetStyledMainTitle(title) l.Styles.Title = titleStyle - m := model[apiclient.Build]{list: l} + m := model[apiclient.BuildDTO]{list: l} p, err := tea.NewProgram(m, tea.WithAltScreen()).Run() if err != nil { @@ -64,7 +64,7 @@ func selectBuildPrompt(builds []apiclient.Build, actionVerb string, choiceChan c os.Exit(1) } - if m, ok := p.(model[apiclient.Build]); ok && m.choice != nil { + if m, ok := p.(model[apiclient.BuildDTO]); ok && m.choice != nil { choiceChan <- m.choice } else { choiceChan <- nil diff --git a/pkg/views/workspace/selection/checkout.go b/pkg/views/selection/checkout.go similarity index 77% rename from pkg/views/workspace/selection/checkout.go rename to pkg/views/selection/checkout.go index 19ee6c23d5..96d3f47580 100644 --- a/pkg/views/workspace/selection/checkout.go +++ b/pkg/views/selection/checkout.go @@ -24,7 +24,7 @@ var ( CheckoutPR = CheckoutOption{Title: "Pull/Merge requests", Id: "pullrequest"} ) -func selectCheckoutPrompt(checkoutOptions []CheckoutOption, projectOrder int, parentIdentifier string, choiceChan chan<- string) { +func selectCheckoutPrompt(checkoutOptions []CheckoutOption, workspaceOrder int, parentIdentifier string, choiceChan chan<- string) { items := []list.Item{} for _, checkoutOption := range checkoutOptions { @@ -38,8 +38,8 @@ func selectCheckoutPrompt(checkoutOptions []CheckoutOption, projectOrder int, pa l := views.GetStyledSelectList(items, listOptions) title := "Cloning Options" - if projectOrder > 1 { - title += fmt.Sprintf(" (Project #%d)", projectOrder) + if workspaceOrder > 1 { + title += fmt.Sprintf(" (Workspace #%d)", workspaceOrder) } l.Title = views.GetStyledMainTitle(title) l.Styles.Title = titleStyle @@ -58,10 +58,10 @@ func selectCheckoutPrompt(checkoutOptions []CheckoutOption, projectOrder int, pa } } -func GetCheckoutOptionFromPrompt(projectOrder int, checkoutOptions []CheckoutOption, parentIdentifier string) CheckoutOption { +func GetCheckoutOptionFromPrompt(workspaceOrder int, checkoutOptions []CheckoutOption, parentIdentifier string) CheckoutOption { choiceChan := make(chan string) - go selectCheckoutPrompt(checkoutOptions, projectOrder, parentIdentifier, choiceChan) + go selectCheckoutPrompt(checkoutOptions, workspaceOrder, parentIdentifier, choiceChan) checkoutOptionId := <-choiceChan diff --git a/pkg/views/workspace/selection/common.go b/pkg/views/selection/common.go similarity index 100% rename from pkg/views/workspace/selection/common.go rename to pkg/views/selection/common.go diff --git a/pkg/views/workspace/selection/gitprovider.go b/pkg/views/selection/gitprovider.go similarity index 81% rename from pkg/views/workspace/selection/gitprovider.go rename to pkg/views/selection/gitprovider.go index 1000f7c420..70dfd61b6f 100644 --- a/pkg/views/workspace/selection/gitprovider.go +++ b/pkg/views/selection/gitprovider.go @@ -17,10 +17,9 @@ import ( var titleStyle = lipgloss.NewStyle() -func selectGitProviderPrompt(gitProviders []gitprovider_view.GitProviderView, projectOrder int, choiceChan chan<- string, samplesEnabled bool) { +func selectGitProviderPrompt(gitProviders []gitprovider_view.GitProviderView, workspaceOrder int, choiceChan chan<- string, samplesEnabled bool) { items := []list.Item{} - // Populate items with titles and descriptions from workspaces. for _, provider := range gitProviders { newItem := item[string]{id: provider.Id, title: fmt.Sprintf("%s (%s)", provider.Name, provider.Alias), choiceProperty: provider.Id} items = append(items, newItem) @@ -37,8 +36,8 @@ func selectGitProviderPrompt(gitProviders []gitprovider_view.GitProviderView, pr l := views.GetStyledSelectList(items) title := "Choose a Git Provider" - if projectOrder > 1 { - title += fmt.Sprintf(" (Project #%d)", projectOrder) + if workspaceOrder > 1 { + title += fmt.Sprintf(" (Workspace #%d)", workspaceOrder) } l.Title = views.GetStyledMainTitle(title) l.Styles.Title = titleStyle @@ -57,9 +56,9 @@ func selectGitProviderPrompt(gitProviders []gitprovider_view.GitProviderView, pr } } -func GetProviderIdFromPrompt(gitProviders []gitprovider_view.GitProviderView, projectOrder int, samplesEnabled bool) string { +func GetProviderIdFromPrompt(gitProviders []gitprovider_view.GitProviderView, workspaceOrder int, samplesEnabled bool) string { choiceChan := make(chan string) - go selectGitProviderPrompt(gitProviders, projectOrder, choiceChan, samplesEnabled) + go selectGitProviderPrompt(gitProviders, workspaceOrder, choiceChan, samplesEnabled) return <-choiceChan } diff --git a/pkg/views/workspace/selection/gitproviderconfig.go b/pkg/views/selection/gitproviderconfig.go similarity index 100% rename from pkg/views/workspace/selection/gitproviderconfig.go rename to pkg/views/selection/gitproviderconfig.go diff --git a/pkg/views/workspace/selection/namespace.go b/pkg/views/selection/namespace.go similarity index 78% rename from pkg/views/workspace/selection/namespace.go rename to pkg/views/selection/namespace.go index 19b4144601..3d454fb31b 100644 --- a/pkg/views/workspace/selection/namespace.go +++ b/pkg/views/selection/namespace.go @@ -13,11 +13,10 @@ import ( "github.com/daytonaio/daytona/pkg/views" ) -func selectNamespacePrompt(namespaces []apiclient.GitNamespace, projectOrder int, selectionListOptions views.SelectionListOptions, choiceChan chan<- string, navChan chan<- string) { +func selectNamespacePrompt(namespaces []apiclient.GitNamespace, workspaceOrder int, selectionListOptions views.SelectionListOptions, choiceChan chan<- string, navChan chan<- string) { items := []list.Item{} var desc string - // Populate items with titles and descriptions from workspaces. for _, namespace := range namespaces { if namespace.Id == "" { desc = "personal" @@ -35,8 +34,8 @@ func selectNamespacePrompt(namespaces []apiclient.GitNamespace, projectOrder int l := views.GetStyledSelectList(items, selectionListOptions) title := "Choose a Namespace" - if projectOrder > 1 { - title += fmt.Sprintf(" (Project #%d)", projectOrder) + if workspaceOrder > 1 { + title += fmt.Sprintf(" (Workspace #%d)", workspaceOrder) } l.Title = views.GetStyledMainTitle(title) l.Styles.Title = titleStyle @@ -61,11 +60,11 @@ func selectNamespacePrompt(namespaces []apiclient.GitNamespace, projectOrder int } } -func GetNamespaceIdFromPrompt(namespaces []apiclient.GitNamespace, projectOrder int, selectionListOptions views.SelectionListOptions) (string, string) { +func GetNamespaceIdFromPrompt(namespaces []apiclient.GitNamespace, workspaceOrder int, selectionListOptions views.SelectionListOptions) (string, string) { choiceChan := make(chan string) navChan := make(chan string) - go selectNamespacePrompt(namespaces, projectOrder, selectionListOptions, choiceChan, navChan) + go selectNamespacePrompt(namespaces, workspaceOrder, selectionListOptions, choiceChan, navChan) select { case choice := <-choiceChan: diff --git a/pkg/views/workspace/selection/prebuild.go b/pkg/views/selection/prebuild.go similarity index 95% rename from pkg/views/workspace/selection/prebuild.go rename to pkg/views/selection/prebuild.go index fee06f6992..44b529e01c 100644 --- a/pkg/views/workspace/selection/prebuild.go +++ b/pkg/views/selection/prebuild.go @@ -25,7 +25,7 @@ func selectPrebuildPrompt(prebuilds []apiclient.PrebuildDTO, actionVerb string, items := []list.Item{} for _, pb := range prebuilds { - title := fmt.Sprintf("%s (%s)", pb.ProjectConfigName, views.GetBranchNameLabel(pb.Branch)) + title := fmt.Sprintf("%s (%s)", pb.WorkspaceTemplateName, views.GetBranchNameLabel(pb.Branch)) desc := pb.Id if pb.CommitInterval != nil { diff --git a/pkg/views/workspace/selection/pullrequest.go b/pkg/views/selection/pullrequest.go similarity index 78% rename from pkg/views/workspace/selection/pullrequest.go rename to pkg/views/selection/pullrequest.go index b81c4a5b7b..13bfe341f0 100644 --- a/pkg/views/workspace/selection/pullrequest.go +++ b/pkg/views/selection/pullrequest.go @@ -14,10 +14,9 @@ import ( tea "github.com/charmbracelet/bubbletea" ) -func selectPullRequestPrompt(pullRequests []apiclient.GitPullRequest, projectOrder int, selectionListOptions views.SelectionListOptions, choiceChan chan<- string, navChan chan<- string) { +func selectPullRequestPrompt(pullRequests []apiclient.GitPullRequest, workspaceOrder int, selectionListOptions views.SelectionListOptions, choiceChan chan<- string, navChan chan<- string) { items := []list.Item{} - // Populate items with titles and descriptions from workspaces. for _, pr := range pullRequests { newItem := item[string]{ id: pr.Name, @@ -35,8 +34,8 @@ func selectPullRequestPrompt(pullRequests []apiclient.GitPullRequest, projectOrd l := views.GetStyledSelectList(items, selectionListOptions) title := "Choose a Pull/Merge Request" - if projectOrder > 1 { - title += fmt.Sprintf(" (Project #%d)", projectOrder) + if workspaceOrder > 1 { + title += fmt.Sprintf(" (Workspace #%d)", workspaceOrder) } l.Title = views.GetStyledMainTitle(title) l.Styles.Title = titleStyle @@ -60,11 +59,11 @@ func selectPullRequestPrompt(pullRequests []apiclient.GitPullRequest, projectOrd } } -func GetPullRequestFromPrompt(pullRequests []apiclient.GitPullRequest, projectOrder int, selectionListOptions views.SelectionListOptions) (*apiclient.GitPullRequest, string) { +func GetPullRequestFromPrompt(pullRequests []apiclient.GitPullRequest, workspaceOrder int, selectionListOptions views.SelectionListOptions) (*apiclient.GitPullRequest, string) { choiceChan := make(chan string) navChan := make(chan string) - go selectPullRequestPrompt(pullRequests, projectOrder, selectionListOptions, choiceChan, navChan) + go selectPullRequestPrompt(pullRequests, workspaceOrder, selectionListOptions, choiceChan, navChan) select { case pullRequestName := <-choiceChan: diff --git a/pkg/views/workspace/selection/repository.go b/pkg/views/selection/repository.go similarity index 76% rename from pkg/views/workspace/selection/repository.go rename to pkg/views/selection/repository.go index d5f5fe92d3..0e9aed6ead 100644 --- a/pkg/views/workspace/selection/repository.go +++ b/pkg/views/selection/repository.go @@ -14,10 +14,9 @@ import ( tea "github.com/charmbracelet/bubbletea" ) -func selectRepositoryPrompt(repositories []apiclient.GitRepository, projectOrder int, choiceChan chan<- string, navChan chan<- string, selectedRepos map[string]int, selectionListOptions views.SelectionListOptions) { +func selectRepositoryPrompt(repositories []apiclient.GitRepository, workspaceOrder int, choiceChan chan<- string, navChan chan<- string, selectedRepos map[string]int, selectionListOptions views.SelectionListOptions) { items := []list.Item{} - // Populate items with titles and descriptions from workspaces. for _, repository := range repositories { newItem := item[string]{ id: repository.Url, @@ -35,8 +34,8 @@ func selectRepositoryPrompt(repositories []apiclient.GitRepository, projectOrder l := views.GetStyledSelectList(items, selectionListOptions) title := "Choose a Repository" - if projectOrder > 1 { - title += fmt.Sprintf(" (Project #%d)", projectOrder) + if workspaceOrder > 1 { + title += fmt.Sprintf(" (Workspace #%d)", workspaceOrder) } l.Title = views.GetStyledMainTitle(title) l.Styles.Title = titleStyle @@ -62,11 +61,11 @@ func selectRepositoryPrompt(repositories []apiclient.GitRepository, projectOrder } } -func GetRepositoryFromPrompt(repositories []apiclient.GitRepository, projectOrder int, selectedRepos map[string]int, selectionListOptions views.SelectionListOptions) (*apiclient.GitRepository, string) { +func GetRepositoryFromPrompt(repositories []apiclient.GitRepository, workspaceOrder int, selectedRepos map[string]int, selectionListOptions views.SelectionListOptions) (*apiclient.GitRepository, string) { choiceChan := make(chan string) navChan := make(chan string) - go selectRepositoryPrompt(repositories, projectOrder, choiceChan, navChan, selectedRepos, selectionListOptions) + go selectRepositoryPrompt(repositories, workspaceOrder, choiceChan, navChan, selectedRepos, selectionListOptions) select { case choice := <-choiceChan: diff --git a/pkg/views/workspace/selection/sample.go b/pkg/views/selection/sample.go similarity index 94% rename from pkg/views/workspace/selection/sample.go rename to pkg/views/selection/sample.go index 708f06d351..5ac672188a 100644 --- a/pkg/views/workspace/selection/sample.go +++ b/pkg/views/selection/sample.go @@ -17,7 +17,6 @@ import ( func selectSamplePrompt(samples []apiclient.Sample, choiceChan chan<- *apiclient.Sample) { items := []list.Item{} - // Populate items with titles and descriptions from workspaces. for _, sample := range samples { newItem := item[apiclient.Sample]{id: sample.Name, title: sample.Name, desc: sample.GitUrl, choiceProperty: sample} items = append(items, newItem) diff --git a/pkg/views/selection/view.go b/pkg/views/selection/view.go new file mode 100644 index 0000000000..cea73f872f --- /dev/null +++ b/pkg/views/selection/view.go @@ -0,0 +1,227 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package selection + +import ( + "fmt" + "io" + "log" + "os" + "strings" + "time" + + "github.com/charmbracelet/bubbles/list" + tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/lipgloss" + "github.com/daytonaio/daytona/cmd/daytona/config" + "github.com/daytonaio/daytona/pkg/views" + "golang.org/x/term" +) + +var CustomRepoIdentifier = "" + +const CREATE_FROM_SAMPLE = "" + +var selectedStyles = lipgloss.NewStyle(). + Border(lipgloss.NormalBorder(), false, false, false, true). + BorderForeground(views.Green). + Bold(true). + Padding(0, 0, 0, 1) + +var statusMessageGreenStyle = lipgloss.NewStyle().Bold(true). + Foreground(lipgloss.AdaptiveColor{Light: "#04B575", Dark: "#04B575"}). + Render + +var statusMessageDangerStyle = lipgloss.NewStyle().Bold(true). + Foreground(lipgloss.AdaptiveColor{Light: "#FF474C", Dark: "#FF474C"}). + Render + +type item[T any] struct { + id, title, desc, createdTime, uptime, targetName string + choiceProperty T + isMarked bool + isMultipleSelect bool + action string +} + +func (i item[T]) Title() string { return i.title } +func (i item[T]) Id() string { return i.id } +func (i item[T]) Description() string { return i.desc } +func (i item[T]) FilterValue() string { return i.title } +func (i item[T]) CreatedTime() string { return i.createdTime } +func (i item[T]) Uptime() string { return i.uptime } +func (i item[T]) TargetName() string { return i.targetName } + +type model[T any] struct { + list list.Model + choice *T + choices []*T + footer string + initialWidthSet bool +} + +func (m model[T]) Init() tea.Cmd { + return nil +} + +func (m model[T]) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + if !m.initialWidthSet { + _, _, err := term.GetSize(int(os.Stdout.Fd())) + if err != nil { + m.list.SetWidth(150) + } + } + + switch msg := msg.(type) { + case tea.KeyMsg: + switch keypress := msg.String(); keypress { + case "ctrl+c": + return m, tea.Quit + + case "enter": + i, ok := m.list.SelectedItem().(item[T]) + if ok { + m.choice = &i.choiceProperty + } + targetList := m.list.Items() + var choices []*T + for _, target := range targetList { + if target.(item[T]).isMarked { + targetItem, ok := target.(item[T]) + if !ok { + continue + } + choices = append(choices, &targetItem.choiceProperty) + } + + } + m.choices = choices + return m, tea.Quit + } + + case tea.WindowSizeMsg: + h, v := views.DocStyle.GetFrameSize() + m.list.SetSize(msg.Width-h, msg.Height-v) + } + + var cmd tea.Cmd + m.list, cmd = m.list.Update(msg) + return m, cmd +} + +func (m model[T]) View() string { + if m.footer == "" { + c, err := config.GetConfig() + if err != nil { + log.Fatal(err) + } + + activeProfile, err := c.GetActiveProfile() + if err != nil { + log.Fatal(err) + } + + m.footer = views.GetListFooter(activeProfile.Name, views.DefaultListFooterPadding) + } + + terminalWidth, terminalHeight, err := term.GetSize(int(os.Stdout.Fd())) + if err != nil { + return "" + } + + if m.list.FilterState() == list.Filtering { + return views.DocStyle.MaxWidth(terminalWidth - 4).MaxHeight(terminalHeight - 4).Render(m.list.View() + m.footer) + } + + return views.DocStyle.MaxWidth(terminalWidth - 4).Height(terminalHeight - 2).Render(m.list.View() + m.footer) +} + +type ItemDelegate[T any] struct { +} + +func (d ItemDelegate[T]) Render(w io.Writer, m list.Model, index int, listItem list.Item) { + i, _ := listItem.(item[T]) // Cast the listItem to your custom item type + s := strings.Builder{} + + var isSelected = index == m.Index() + + baseStyles := lipgloss.NewStyle().Padding(0, 0, 0, 2) + + title := baseStyles.Render(i.Title()) + idWithTargetConfigString := fmt.Sprintf("%s (%s)", i.Id(), i.TargetName()) + idWithTargetConfig := baseStyles.Foreground(views.Gray).Render(idWithTargetConfigString) + description := baseStyles.Render(i.Description()) + + // Add the created/updated time if it's available + timeWidth := m.Width() - baseStyles.GetHorizontalFrameSize() - lipgloss.Width(title) + timeStyles := lipgloss.NewStyle(). + Align(lipgloss.Right). + Width(timeWidth) + timeString := timeStyles.Render("") + if i.Uptime() != "" { + timeString = timeStyles.Render(i.Uptime()) + } else if i.CreatedTime() != "" { + timeString = timeStyles.Render(fmt.Sprintf("created %s", i.CreatedTime())) + } + + // Adjust styles as the user moves through the menu + if isSelected { + title = selectedStyles.Foreground(views.Green).Render(i.Title()) + idWithTargetConfig = selectedStyles.Foreground(views.Gray).Render(idWithTargetConfigString) + description = selectedStyles.Foreground(views.DimmedGreen).Render(i.Description()) + timeString = timeStyles.Foreground(views.DimmedGreen).Render(timeString) + } + + // Render to the terminal + s.WriteString(lipgloss.JoinHorizontal(lipgloss.Bottom, title, timeString)) + s.WriteRune('\n') + s.WriteString(idWithTargetConfig) + s.WriteRune('\n') + s.WriteString(description) + s.WriteRune('\n') + + fmt.Fprint(w, s.String()) +} + +func (d ItemDelegate[T]) Height() int { + height := lipgloss.NewStyle().GetVerticalFrameSize() + 4 + return height +} + +func (d ItemDelegate[T]) Spacing() int { + return 0 +} + +func (d ItemDelegate[T]) Update(msg tea.Msg, m *list.Model) tea.Cmd { + i, ok := m.SelectedItem().(item[T]) + if !ok { + return nil + } + + m.StatusMessageLifetime = time.Millisecond * 2000 + + var title string + switch msg := msg.(type) { + case tea.KeyMsg: + switch keypress := msg.String(); keypress { + case "x": + if !i.isMultipleSelect { + return nil + } + if i.isMarked { + i.title = strings.TrimPrefix(i.title, statusMessageDangerStyle(fmt.Sprintf("%s: ", i.action))) + i.isMarked = false + m.SetItem(m.Index(), i) + return m.NewStatusMessage(statusMessageGreenStyle("Removed target from list: ") + statusMessageGreenStyle(i.title)) + } + + title = i.title + i.title = statusMessageDangerStyle(fmt.Sprintf("%s: ", i.action)) + statusMessageGreenStyle(i.title) + i.isMarked = true + m.SetItem(m.Index(), i) + return m.NewStatusMessage(statusMessageDangerStyle("Added target to list: ") + statusMessageGreenStyle(title)) + } + } + return nil +} diff --git a/pkg/views/workspace/selection/projectrequest.go b/pkg/views/selection/workspacerequest.go similarity index 55% rename from pkg/views/workspace/selection/projectrequest.go rename to pkg/views/selection/workspacerequest.go index 81e1449713..3f035ce58a 100644 --- a/pkg/views/workspace/selection/projectrequest.go +++ b/pkg/views/selection/workspacerequest.go @@ -19,60 +19,60 @@ import ( ) var doneConfiguringName = "DoneConfiguringName" -var DoneConfiguring = apiclient.CreateProjectDTO{ +var DoneConfiguring = apiclient.CreateWorkspaceDTO{ Name: doneConfiguringName, } -type projectRequestItem struct { - item[apiclient.CreateProjectDTO] +type workspaceRequestItem struct { + item[apiclient.CreateWorkspaceDTO] name, image, user, devcontainerConfig string - project apiclient.CreateProjectDTO + workspace apiclient.CreateWorkspaceDTO } -type projectRequestItemDelegate struct { - ItemDelegate[apiclient.CreateProjectDTO] +type workspaceRequestItemDelegate struct { + ItemDelegate[apiclient.CreateWorkspaceDTO] } -type projectRequestModel struct { - model[apiclient.CreateProjectDTO] +type workspaceRequestModel struct { + model[apiclient.CreateWorkspaceDTO] } -func selectProjectRequestPrompt(projects *[]apiclient.CreateProjectDTO, choiceChan chan<- *apiclient.CreateProjectDTO) { +func selectWorkspaceRequestPrompt(workspaces *[]apiclient.CreateWorkspaceDTO, choiceChan chan<- *apiclient.CreateWorkspaceDTO) { items := []list.Item{} - for _, project := range *projects { + for _, workspace := range *workspaces { var name string var image string var user string var devcontainerConfig string - name = fmt.Sprintf("%s %s", "Project:", project.Name) - if project.Image != nil { - image = fmt.Sprintf("%s %s", "Image:", *project.Image) + name = fmt.Sprintf("%s %s", "Workspace:", workspace.Name) + if workspace.Image != nil { + image = fmt.Sprintf("%s %s", "Image:", *workspace.Image) } - if project.User != nil { - user = fmt.Sprintf("%s %s", "User:", *project.User) + if workspace.User != nil { + user = fmt.Sprintf("%s %s", "User:", *workspace.User) } - if project.BuildConfig != nil && project.BuildConfig.Devcontainer != nil { - devcontainerConfig = fmt.Sprintf("%s %s", "Devcontainer Config:", project.BuildConfig.Devcontainer.FilePath) + if workspace.BuildConfig != nil && workspace.BuildConfig.Devcontainer != nil { + devcontainerConfig = fmt.Sprintf("%s %s", "Devcontainer Config:", workspace.BuildConfig.Devcontainer.FilePath) } - newItem := projectRequestItem{name: name, image: image, user: user, project: project, devcontainerConfig: devcontainerConfig} + newItem := workspaceRequestItem{name: name, image: image, user: user, workspace: workspace, devcontainerConfig: devcontainerConfig} newItem.SetId(name) items = append(items, newItem) } - newItem := projectRequestItem{name: "Done configuring", image: "Return to summary view", user: "", project: DoneConfiguring} + newItem := workspaceRequestItem{name: "Done configuring", image: "Return to summary view", user: "", workspace: DoneConfiguring} items = append(items, newItem) l := views.GetStyledSelectList(items) - l.SetDelegate(projectRequestItemDelegate{}) + l.SetDelegate(workspaceRequestItemDelegate{}) - m := projectRequestModel{} + m := workspaceRequestModel{} m.list = l - m.list.Title = "Choose a Project To Configure" + m.list.Title = "Choose a Workspace To Configure" m.list.AdditionalShortHelpKeys = func() []key.Binding { return []key.Binding{ @@ -89,22 +89,22 @@ func selectProjectRequestPrompt(projects *[]apiclient.CreateProjectDTO, choiceCh os.Exit(1) } - if m, ok := p.(projectRequestModel); ok && m.choice != nil { + if m, ok := p.(workspaceRequestModel); ok && m.choice != nil { choiceChan <- m.choice } else { choiceChan <- nil } } -func GetProjectRequestFromPrompt(projects *[]apiclient.CreateProjectDTO) *apiclient.CreateProjectDTO { - choiceChan := make(chan *apiclient.CreateProjectDTO) +func GetWorkspaceRequestFromPrompt(workspaces *[]apiclient.CreateWorkspaceDTO) *apiclient.CreateWorkspaceDTO { + choiceChan := make(chan *apiclient.CreateWorkspaceDTO) - go selectProjectRequestPrompt(projects, choiceChan) + go selectWorkspaceRequestPrompt(workspaces, choiceChan) return <-choiceChan } -func (m projectRequestModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { +func (m workspaceRequestModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg := msg.(type) { case tea.KeyMsg: switch keypress := msg.String(); keypress { @@ -112,9 +112,9 @@ func (m projectRequestModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m, tea.Quit case "enter": - i, ok := m.list.SelectedItem().(projectRequestItem) + i, ok := m.list.SelectedItem().(workspaceRequestItem) if ok { - m.choice = &i.project + m.choice = &i.workspace } return m, tea.Quit case "f10": @@ -131,8 +131,8 @@ func (m projectRequestModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m, cmd } -func (d projectRequestItemDelegate) Render(w io.Writer, m list.Model, index int, listItem list.Item) { - i, _ := listItem.(projectRequestItem) +func (d workspaceRequestItemDelegate) Render(w io.Writer, m list.Model, index int, listItem list.Item) { + i, _ := listItem.(workspaceRequestItem) s := strings.Builder{} var isSelected = index == m.Index() @@ -153,7 +153,7 @@ func (d projectRequestItemDelegate) Render(w io.Writer, m list.Model, index int, } // Render to the terminal - if i.project.Name == DoneConfiguring.Name { + if i.workspace.Name == DoneConfiguring.Name { s.WriteRune('\n') s.WriteString(name) s.WriteRune('\n') @@ -177,13 +177,13 @@ func (d projectRequestItemDelegate) Render(w io.Writer, m list.Model, index int, fmt.Fprint(w, s.String()) } -func (d projectRequestItemDelegate) Height() int { +func (d workspaceRequestItemDelegate) Height() int { height := lipgloss.NewStyle().GetVerticalFrameSize() + 10 return height } -func (i projectRequestItem) Name() string { return i.name } -func (i projectRequestItem) Image() string { return i.image } -func (i projectRequestItem) User() string { return i.user } -func (i projectRequestItem) DevcontainerConfig() string { return i.devcontainerConfig } -func (i projectRequestItem) SetId(id string) { i.id = id } +func (i workspaceRequestItem) Name() string { return i.name } +func (i workspaceRequestItem) Image() string { return i.image } +func (i workspaceRequestItem) User() string { return i.user } +func (i workspaceRequestItem) DevcontainerConfig() string { return i.devcontainerConfig } +func (i workspaceRequestItem) SetId(id string) { i.id = id } diff --git a/pkg/views/selection/workspacetemplate.go b/pkg/views/selection/workspacetemplate.go new file mode 100644 index 0000000000..d8548dbc27 --- /dev/null +++ b/pkg/views/selection/workspacetemplate.go @@ -0,0 +1,93 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package selection + +import ( + "fmt" + "os" + + "github.com/daytonaio/daytona/pkg/apiclient" + "github.com/daytonaio/daytona/pkg/views" + + "github.com/charmbracelet/bubbles/list" + tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/lipgloss" +) + +var BlankWorkspaceIdentifier = "" +var NewWorkspaceTemplateIdentifier = "" + +func GetWorkspaceTemplateFromPrompt(workspaceTemplates []apiclient.WorkspaceTemplate, workspaceOrder int, showBlankOption, withNewWorkspaceTemplate bool, actionVerb string) *apiclient.WorkspaceTemplate { + choiceChan := make(chan *apiclient.WorkspaceTemplate) + go selectWorkspaceTemplatePrompt(workspaceTemplates, workspaceOrder, showBlankOption, withNewWorkspaceTemplate, actionVerb, choiceChan) + return <-choiceChan +} + +func selectWorkspaceTemplatePrompt(workspaceTemplates []apiclient.WorkspaceTemplate, workspaceOrder int, showBlankOption, withNewWorkspaceTemplate bool, actionVerb string, choiceChan chan<- *apiclient.WorkspaceTemplate) { + items := []list.Item{} + + if showBlankOption { + newItem := item[apiclient.WorkspaceTemplate]{title: "Make a blank workspace", desc: "(default workspace configuration)", choiceProperty: apiclient.WorkspaceTemplate{ + Name: BlankWorkspaceIdentifier, + }} + items = append(items, newItem) + } + + for _, wt := range workspaceTemplates { + workspaceTemplateName := wt.Name + if wt.Name == "" { + workspaceTemplateName = "Unnamed Workspace Template" + } + + newItem := item[apiclient.WorkspaceTemplate]{title: workspaceTemplateName, desc: wt.RepositoryUrl, choiceProperty: wt} + items = append(items, newItem) + } + + if withNewWorkspaceTemplate { + newItem := item[apiclient.WorkspaceTemplate]{title: "+ Create a new workspace template", desc: "", choiceProperty: apiclient.WorkspaceTemplate{ + Name: NewWorkspaceTemplateIdentifier, + }} + items = append(items, newItem) + } + + d := list.NewDefaultDelegate() + + d.Styles.SelectedTitle = lipgloss.NewStyle(). + Border(lipgloss.NormalBorder(), false, false, false, true). + BorderForeground(views.Green). + Foreground(views.Green). + Bold(true). + Padding(0, 0, 0, 1) + + d.Styles.SelectedDesc = d.Styles.SelectedTitle.Foreground(views.DimmedGreen) + + l := list.New(items, d, 0, 0) + + l.Styles.FilterPrompt = lipgloss.NewStyle().Foreground(views.Green) + l.Styles.FilterCursor = lipgloss.NewStyle().Foreground(views.Green) + + l.FilterInput.PromptStyle = lipgloss.NewStyle().Foreground(views.Green) + l.FilterInput.TextStyle = lipgloss.NewStyle().Foreground(views.Green) + + title := "Select a Workspace Template To " + actionVerb + if workspaceOrder > 1 { + title += fmt.Sprintf(" (Workspace #%d)", workspaceOrder) + } + l.Title = views.GetStyledMainTitle(title) + l.Styles.Title = titleStyle + + m := model[apiclient.WorkspaceTemplate]{list: l} + + p, err := tea.NewProgram(m, tea.WithAltScreen()).Run() + if err != nil { + fmt.Println("Error running program:", err) + os.Exit(1) + } + + if m, ok := p.(model[apiclient.WorkspaceTemplate]); ok && m.choice != nil { + choiceChan <- m.choice + } else { + choiceChan <- nil + } +} diff --git a/pkg/views/server/config.go b/pkg/views/server/config.go index 38ef02e011..af558a9644 100644 --- a/pkg/views/server/config.go +++ b/pkg/views/server/config.go @@ -23,9 +23,9 @@ func RenderConfig(config *server.Config) { output += fmt.Sprintf("%s %d", views.GetPropertyKey("API Port: "), config.ApiPort) + "\n\n" - output += fmt.Sprintf("%s %s", views.GetPropertyKey("Default Project Image: "), config.DefaultProjectImage) + "\n\n" + output += fmt.Sprintf("%s %s", views.GetPropertyKey("Default Workspace Image: "), config.DefaultWorkspaceImage) + "\n\n" - output += fmt.Sprintf("%s %s", views.GetPropertyKey("Default Project User: "), config.DefaultProjectUser) + "\n\n" + output += fmt.Sprintf("%s %s", views.GetPropertyKey("Default Workspace User: "), config.DefaultWorkspaceUser) + "\n\n" output += fmt.Sprintf("%s %s", views.GetPropertyKey("FRPS Domain: "), config.Frps.Domain) + "\n\n" @@ -61,7 +61,9 @@ func RenderConfig(config *server.Config) { output += fmt.Sprintf("%s %s", views.GetPropertyKey("Build Image Namespace: "), config.BuildImageNamespace) + "\n\n" - output += fmt.Sprintf("%s %s", views.GetPropertyKey("Providers Dir: "), config.ProvidersDir) + "\n\n" + if config.LocalRunnerDisabled != nil && *config.LocalRunnerDisabled { + output += fmt.Sprintf("%s %s", views.GetPropertyKey("Local Runner Disabled: "), "Yes") + "\n\n" + } output += fmt.Sprintf("%s %s", views.GetPropertyKey("Registry URL: "), config.RegistryUrl) + "\n\n" @@ -76,9 +78,9 @@ func RenderConfig(config *server.Config) { output += "If you want to connect to the server remotely:\n\n" output += "1. Create an API key on this machine: " - output += lipgloss.NewStyle().Foreground(views.Green).Render("daytona api-key new") + "\n" + output += lipgloss.NewStyle().Foreground(views.Green).Render("daytona api-key create") + "\n" output += "2. Add a profile on the client machine: \n\t" - output += lipgloss.NewStyle().Foreground(views.Green).Render(fmt.Sprintf("daytona profile add -a %s -k API_KEY", apiUrl)) + output += lipgloss.NewStyle().Foreground(views.Green).Render(fmt.Sprintf("daytona profile create -a %s -k API_KEY", apiUrl)) views.RenderContainerLayout(views.GetInfoMessage(output)) } diff --git a/pkg/views/server/configure.go b/pkg/views/server/configure.go index 6808c3a5a7..7d03f2ed71 100644 --- a/pkg/views/server/configure.go +++ b/pkg/views/server/configure.go @@ -14,6 +14,7 @@ import ( "github.com/charmbracelet/huh" "github.com/daytonaio/daytona/pkg/apiclient" "github.com/daytonaio/daytona/pkg/views" + "github.com/daytonaio/daytona/pkg/views/util" ) type Model struct { @@ -28,7 +29,7 @@ type keymap struct { submit key.Binding } -func NewModel(config *apiclient.ServerConfig, containerRegistries []apiclient.ContainerRegistry) Model { +func NewModel(config *apiclient.ServerConfig) Model { m := Model{ config: config, help: help.New(), @@ -37,33 +38,21 @@ func NewModel(config *apiclient.ServerConfig, containerRegistries []apiclient.Co }, } - m.form = m.createForm(containerRegistries) + m.form = m.createForm() return m } -func (m *Model) createForm(containerRegistries []apiclient.ContainerRegistry) *huh.Form { +func (m *Model) createForm() *huh.Form { apiPortView := strconv.Itoa(int(m.config.GetApiPort())) headscalePortView := strconv.Itoa(int(m.config.GetHeadscalePort())) frpsPortView := strconv.Itoa(int(m.config.Frps.GetPort())) localBuilderRegistryPort := strconv.Itoa(int(m.config.GetLocalBuilderRegistryPort())) - builderContainerRegistryOptions := []huh.Option[string]{{ - Key: "Local registry managed by Daytona", - Value: "local", - }} - for _, cr := range containerRegistries { - builderContainerRegistryOptions = append(builderContainerRegistryOptions, huh.Option[string]{Key: cr.Server, Value: cr.Server}) - } - logFileMaxSize := strconv.Itoa(int(m.config.LogFile.MaxSize)) logFileMaxBackups := strconv.Itoa(int(m.config.LogFile.MaxBackups)) logFileMaxAge := strconv.Itoa(int(m.config.LogFile.MaxAge)) return huh.NewForm( huh.NewGroup( - huh.NewInput(). - Title("Providers Directory"). - Description("Directory will be created if it does not exist"). - Value(&m.config.ProvidersDir), huh.NewInput(). Title("Registry URL"). Value(&m.config.RegistryUrl), @@ -77,23 +66,20 @@ func (m *Model) createForm(containerRegistries []apiclient.ContainerRegistry) *h ), huh.NewGroup( huh.NewInput(). - Title("Default Project Image"). - Value(&m.config.DefaultProjectImage), + Title("Default Workspace Image"). + Value(&m.config.DefaultWorkspaceImage), huh.NewInput(). - Title("Default Project User"). - Value(&m.config.DefaultProjectUser), + Title("Default Workspace User"). + Value(&m.config.DefaultWorkspaceUser), ), huh.NewGroup( huh.NewInput(). Title("Builder Image"). Description("Image dependencies: docker, socat, git, @devcontainers/cli (node package)"). Value(&m.config.BuilderImage), - huh.NewSelect[string](). - Title("Builder Registry"). - Description("To add options, add a container registry with 'daytona cr set'"). - Options( - builderContainerRegistryOptions..., - ). + huh.NewInput(). + Title("Builder Registry Server"). + Description("Add container registry credentials to the server by adding them as environment variables using `daytona env set`"). Value(&m.config.BuilderRegistryServer), huh.NewInput(). Title("Build Image Namespace"). @@ -104,10 +90,14 @@ func (m *Model) createForm(containerRegistries []apiclient.ContainerRegistry) *h huh.NewInput(). Title("Local Builder Registry Port"). Value(&localBuilderRegistryPort). - Validate(createPortValidator(m.config, &localBuilderRegistryPort, &m.config.LocalBuilderRegistryPort)), + Validate(util.CreateServerPortValidator(m.config, &localBuilderRegistryPort, &m.config.LocalBuilderRegistryPort)), huh.NewInput(). Title("Local Builder Registry Image"). Value(&m.config.LocalBuilderRegistryImage), + huh.NewConfirm(). + Title("Local Runner Disabled"). + Description("Disables the local runner"). + Value(m.config.LocalRunnerDisabled), ).WithHideFunc(func() bool { return m.config.BuilderRegistryServer != "local" }), @@ -115,11 +105,11 @@ func (m *Model) createForm(containerRegistries []apiclient.ContainerRegistry) *h huh.NewInput(). Title("API Port"). Value(&apiPortView). - Validate(createPortValidator(m.config, &apiPortView, &m.config.ApiPort)), + Validate(util.CreateServerPortValidator(m.config, &apiPortView, &m.config.ApiPort)), huh.NewInput(). Title("Headscale Port"). Value(&headscalePortView). - Validate(createPortValidator(m.config, &headscalePortView, &m.config.HeadscalePort)), + Validate(util.CreateServerPortValidator(m.config, &headscalePortView, &m.config.HeadscalePort)), huh.NewInput(). Title("Binaries Path"). Description("Directory will be created if it does not exist"). @@ -142,16 +132,16 @@ func (m *Model) createForm(containerRegistries []apiclient.ContainerRegistry) *h Title("Log File Max Size"). Description("In megabytes"). Value(&logFileMaxSize). - Validate(createIntValidator(&logFileMaxSize, &m.config.LogFile.MaxSize)), + Validate(util.CreateIntValidator(&logFileMaxSize, &m.config.LogFile.MaxSize)), huh.NewInput(). Title("Log File Max Backups"). Value(&logFileMaxBackups). - Validate(createIntValidator(&logFileMaxBackups, &m.config.LogFile.MaxBackups)), + Validate(util.CreateIntValidator(&logFileMaxBackups, &m.config.LogFile.MaxBackups)), huh.NewInput(). Title("Log File Max Age"). Description("In days"). Value(&logFileMaxAge). - Validate(createIntValidator(&logFileMaxAge, &m.config.LogFile.MaxAge)), + Validate(util.CreateIntValidator(&logFileMaxAge, &m.config.LogFile.MaxAge)), huh.NewConfirm(). Title("Log File Local Time"). Description("Used for timestamping files. Default is UTC time."). @@ -167,7 +157,7 @@ func (m *Model) createForm(containerRegistries []apiclient.ContainerRegistry) *h huh.NewInput(). Title("Frps Port"). Value(&frpsPortView). - Validate(createPortValidator(m.config, &frpsPortView, &m.config.Frps.Port)), + Validate(util.CreateServerPortValidator(m.config, &frpsPortView, &m.config.Frps.Port)), huh.NewInput(). Title("Frps Protocol"). Value(&m.config.Frps.Protocol), @@ -232,8 +222,8 @@ func (m Model) View() string { return m.form.View() + helpView } -func ConfigurationForm(config *apiclient.ServerConfig, containerRegistries []apiclient.ContainerRegistry) (*apiclient.ServerConfig, error) { - m := NewModel(config, containerRegistries) +func ConfigurationForm(config *apiclient.ServerConfig) (*apiclient.ServerConfig, error) { + m := NewModel(config) p, err := tea.NewProgram(m, tea.WithAltScreen()).Run() @@ -247,39 +237,3 @@ func ConfigurationForm(config *apiclient.ServerConfig, containerRegistries []api return nil, errors.New("no changes were made") } - -func createPortValidator(config *apiclient.ServerConfig, portView *string, port *int32) func(string) error { - return func(string) error { - validatePort, err := strconv.Atoi(*portView) - if err != nil { - return errors.New("failed to parse port") - } - if validatePort < 0 || validatePort > 65535 { - return errors.New("port out of range") - } - *port = int32(validatePort) - - if config.ApiPort == config.HeadscalePort { - return errors.New("port conflict") - } - - return nil - } -} - -func createIntValidator(viewValue *string, value *int32) func(string) error { - return func(string) error { - validateInt, err := strconv.Atoi(*viewValue) - if err != nil { - return errors.New("failed to parse int") - } - - if validateInt <= 0 { - return errors.New("int out of range") - } - - *value = int32(validateInt) - - return nil - } -} diff --git a/pkg/views/server/runner/create.go b/pkg/views/server/runner/create.go new file mode 100644 index 0000000000..29a23e6500 --- /dev/null +++ b/pkg/views/server/runner/create.go @@ -0,0 +1,33 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package runner + +import ( + "errors" + + "github.com/daytonaio/daytona/pkg/views" + + "github.com/charmbracelet/huh" +) + +func RunnerCreationView(name *string, existingNames []string) error { + return huh.NewForm( + huh.NewGroup( + huh.NewInput(). + Title("Runner Name"). + Value(name). + Validate(func(str string) error { + if str == "" { + return errors.New("name can not be blank") + } + for _, a := range existingNames { + if a == str { + return errors.New("name already in use") + } + } + return nil + }), + ), + ).WithHeight(5).WithTheme(views.GetCustomTheme()).Run() +} diff --git a/pkg/views/server/runner/info/view.go b/pkg/views/server/runner/info/view.go new file mode 100644 index 0000000000..58d83e6a85 --- /dev/null +++ b/pkg/views/server/runner/info/view.go @@ -0,0 +1,70 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package info + +import ( + "fmt" + "os" + + "github.com/charmbracelet/lipgloss" + "github.com/daytonaio/daytona/pkg/apiclient" + "github.com/daytonaio/daytona/pkg/views" + "golang.org/x/term" +) + +const propertyNameWidth = 20 + +var propertyNameStyle = lipgloss.NewStyle(). + Foreground(views.LightGray) + +var propertyValueStyle = lipgloss.NewStyle(). + Foreground(views.Light). + Bold(true) + +func Render(runner *apiclient.RunnerDTO, forceUnstyled bool) { + var output string + output += "\n\n" + + output += views.GetStyledMainTitle("Runner Info") + "\n\n" + + output += getInfoLine("Name", runner.Name) + "\n" + + output += getInfoLine("ID", runner.Id) + "\n" + + output += getInfoLine("State", views.GetStateLabel(runner.State.Name)) + "\n" + + if runner.State.Error != nil { + output += getInfoLine("Error", *runner.State.Error) + "\n" + } + + terminalWidth, _, err := term.GetSize(int(os.Stdout.Fd())) + if err != nil { + fmt.Println(output) + return + } + if terminalWidth < views.TUITableMinimumWidth || forceUnstyled { + renderUnstyledInfo(output) + return + } + + renderTUIView(output, views.GetContainerBreakpointWidth(terminalWidth)) +} + +func renderUnstyledInfo(output string) { + fmt.Println(output) +} + +func renderTUIView(output string, width int) { + output = lipgloss.NewStyle().PaddingLeft(3).Render(output) + + content := lipgloss. + NewStyle().Width(width). + Render(output) + + fmt.Println(content) +} + +func getInfoLine(key, value string) string { + return propertyNameStyle.Render(fmt.Sprintf("%-*s", propertyNameWidth, key)) + propertyValueStyle.Render(value) + "\n" +} diff --git a/pkg/views/server/runner/list/view.go b/pkg/views/server/runner/list/view.go new file mode 100644 index 0000000000..ba1b39a65e --- /dev/null +++ b/pkg/views/server/runner/list/view.go @@ -0,0 +1,65 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package list + +import ( + "fmt" + + "github.com/daytonaio/daytona/pkg/apiclient" + "github.com/daytonaio/daytona/pkg/views" + "github.com/daytonaio/daytona/pkg/views/server/runner/info" + "github.com/daytonaio/daytona/pkg/views/util" + views_util "github.com/daytonaio/daytona/pkg/views/util" +) + +type rowData struct { + Name string + Id string + State string +} + +func ListRunners(runnerList []apiclient.RunnerDTO) { + if len(runnerList) == 0 { + views_util.NotifyEmptyRunnerList(true) + return + } + + data := [][]string{} + + for _, p := range runnerList { + data = append(data, getRowFromData(p)) + } + + table := util.GetTableView(data, []string{ + "Name", "ID", "State", + }, nil, func() { + renderUnstyledList(runnerList) + }) + + fmt.Println(table) +} + +func renderUnstyledList(runnerList []apiclient.RunnerDTO) { + for _, p := range runnerList { + info.Render(&p, true) + + if p.Id != runnerList[len(runnerList)-1].Id { + fmt.Printf("\n%s\n\n", views.SeparatorString) + } + } +} + +func getRowFromData(runner apiclient.RunnerDTO) []string { + var data rowData + + data.Name = runner.Name + views_util.AdditionalPropertyPadding + data.Id = runner.Id + data.State = views.GetStateLabel(runner.State.Name) + + return []string{ + views.NameStyle.Render(data.Name), + views.DefaultRowDataStyle.Render(data.Id), + data.State, + } +} diff --git a/pkg/views/server/runner/notify.go b/pkg/views/server/runner/notify.go new file mode 100644 index 0000000000..a8cd4a5dd8 --- /dev/null +++ b/pkg/views/server/runner/notify.go @@ -0,0 +1,35 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package runner + +import ( + "fmt" + + "github.com/atotto/clipboard" + "github.com/charmbracelet/lipgloss" + "github.com/daytonaio/daytona/pkg/apiclient" + "github.com/daytonaio/daytona/pkg/views" +) + +func Notify(runner *apiclient.CreateRunnerResultDTO, apiUrl, clientId string, telemetryDisabled bool) { + var output string + + output += fmt.Sprintf("You can connect the Runner %s to the Daytona Server by running this command on the Runner's machine:", runner.Name) + + views.RenderContainerLayout(views.GetInfoMessage(output)) + + command := fmt.Sprintf("daytona runner configure --api-url %s --api-key %s --id %s --name %s --client-id %s", apiUrl, runner.ApiKey, runner.Id, runner.Name, clientId) + if telemetryDisabled { + command += " --disable-telemetry" + } + fmt.Println(lipgloss.NewStyle().Padding(0).Foreground(views.Green).Render(command)) + + if err := clipboard.WriteAll(command); err == nil { + output = "The command has been copied to your clipboard." + } else { + output = "Make sure to copy it as you will not be able to see it again." + } + + views.RenderContainerLayout(views.GetInfoMessage(output)) +} diff --git a/pkg/views/containerregistry/select.go b/pkg/views/server/runner/selection/select.go similarity index 51% rename from pkg/views/containerregistry/select.go rename to pkg/views/server/runner/selection/select.go index 914c27087c..d2b367b901 100644 --- a/pkg/views/containerregistry/select.go +++ b/pkg/views/server/runner/selection/select.go @@ -1,41 +1,38 @@ // Copyright 2024 Daytona Platforms Inc. // SPDX-License-Identifier: Apache-2.0 -package containerregistry +package runner import ( "github.com/charmbracelet/bubbles/list" tea "github.com/charmbracelet/bubbletea" - "github.com/daytonaio/daytona/internal/util" "github.com/daytonaio/daytona/pkg/apiclient" "github.com/daytonaio/daytona/pkg/common" "github.com/daytonaio/daytona/pkg/views" ) -const NewRegistryServerIdentifier = "+ New Container Registry" +const NewTargetConfigName = "+ New Target Config" -func GetRegistryFromPrompt(registries []apiclient.ContainerRegistry, activeProfileName string, withNewRegistry bool) (*apiclient.ContainerRegistry, error) { - items := util.ArrayMap(registries, func(r apiclient.ContainerRegistry) list.Item { - return item{ - registry: r, - } - }) +type RunnerView struct { + Id string + Name string +} + +func GetRunnerFromPrompt(runners []apiclient.RunnerDTO, activeProfileName string, actionVerb string) (*RunnerView, error) { + items := []list.Item{} - if withNewRegistry { - name := NewRegistryServerIdentifier - emptyString := "" + for _, r := range runners { items = append(items, item{ - registry: apiclient.ContainerRegistry{ - Password: emptyString, - Username: emptyString, - Server: name, + runner: RunnerView{ + Id: r.Id, + Name: r.Name, }, }) } l := views.GetStyledSelectList(items) m := model{list: l} - m.list.Title = "Choose a container registry" + m.list.Title = views.GetStyledMainTitle("Choose a Runner To " + actionVerb) m.footer = views.GetListFooter(activeProfileName, views.DefaultListFooterPadding) p, err := tea.NewProgram(m, tea.WithAltScreen()).Run() diff --git a/pkg/views/containerregistry/view.go b/pkg/views/server/runner/selection/view.go similarity index 61% rename from pkg/views/containerregistry/view.go rename to pkg/views/server/runner/selection/view.go index 24392c00f7..3af5aec750 100644 --- a/pkg/views/containerregistry/view.go +++ b/pkg/views/server/runner/selection/view.go @@ -1,31 +1,30 @@ // Copyright 2024 Daytona Platforms Inc. // SPDX-License-Identifier: Apache-2.0 -package containerregistry +package runner import ( + "fmt" + "os" + "github.com/charmbracelet/bubbles/list" tea "github.com/charmbracelet/bubbletea" - "github.com/daytonaio/daytona/pkg/apiclient" "github.com/daytonaio/daytona/pkg/views" + "golang.org/x/term" ) type item struct { - registry apiclient.ContainerRegistry + runner RunnerView } -func (i item) Title() string { return i.registry.Server } -func (i item) Description() string { - if i.registry.Server == NewRegistryServerIdentifier { - return "Add a new container registry" - } - return i.registry.Username -} -func (i item) FilterValue() string { return i.registry.Server } +func (i item) Title() string { return i.runner.Name } + +func (i item) Description() string { return i.runner.Id } +func (i item) FilterValue() string { return fmt.Sprintf("%s%s", i.runner.Id, i.runner.Name) } type model struct { list list.Model - choice *apiclient.ContainerRegistry + choice *RunnerView footer string } @@ -43,7 +42,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { case "enter": i, ok := m.list.SelectedItem().(item) if ok { - m.choice = &i.registry + m.choice = &i.runner } return m, tea.Quit } @@ -58,5 +57,10 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } func (m model) View() string { - return views.DocStyle.Render(m.list.View() + m.footer) + terminalWidth, terminalHeight, err := term.GetSize(int(os.Stdout.Fd())) + if err != nil { + return "" + } + + return views.DocStyle.Width(terminalWidth - 4).Height(terminalHeight - 4).Render(m.list.View() + m.footer) } diff --git a/pkg/views/styles.go b/pkg/views/styles.go index 08c2310884..a38ffafacb 100644 --- a/pkg/views/styles.go +++ b/pkg/views/styles.go @@ -31,6 +31,18 @@ var ( Red = lipgloss.AdaptiveColor{Light: "#FF4672", Dark: "#ED567A"} ) +var ( + ColorPending = lipgloss.AdaptiveColor{Light: "#cce046", Dark: "#cce046"} + ColorSuccess = lipgloss.AdaptiveColor{Light: "#2ecc71", Dark: "#2ecc71"} + ColorStarting = ColorSuccess + ColorStopped = lipgloss.AdaptiveColor{Light: "#a2a2a2", Dark: "#a2a2a2"} + ColorStopping = ColorStopped + ColorError = lipgloss.AdaptiveColor{Light: "#e74c3c", Dark: "#e74c3c"} + ColorDeleting = ColorStopped + ColorDeleted = ColorStopped + ColorUnresponsive = ColorError +) + var ( BaseTableStyleHorizontalPadding = 4 BaseTableStyle = lipgloss.NewStyle(). @@ -47,6 +59,22 @@ var ( TableHeaderStyle = BaseCellStyle.Foreground(LightGray).Bold(false).Padding(0).MarginRight(4) ) +var ( + UndefinedStyle = lipgloss.NewStyle().Foreground(ColorPending) + PendingStyle = lipgloss.NewStyle().Foreground(ColorPending) + RunningStyle = lipgloss.NewStyle().Foreground(ColorPending) + RunSuccessfulStyle = lipgloss.NewStyle().Foreground(ColorSuccess) + CreatingStyle = lipgloss.NewStyle().Foreground(ColorPending) + StartedStyle = lipgloss.NewStyle().Foreground(ColorSuccess) + StartingStyle = lipgloss.NewStyle().Foreground(ColorStarting) + StoppedStyle = lipgloss.NewStyle().Foreground(ColorStopped) + StoppingStyle = lipgloss.NewStyle().Foreground(ColorStopping) + ErrorStyle = lipgloss.NewStyle().Foreground(ColorError) + DeletingStyle = lipgloss.NewStyle().Foreground(ColorDeleting) + DeletedStyle = lipgloss.NewStyle().Foreground(ColorDeleted) + UnresponsiveStyle = lipgloss.NewStyle().Foreground(ColorUnresponsive) +) + var LogPrefixColors = []lipgloss.AdaptiveColor{ Blue, Orange, Cyan, Yellow, } diff --git a/pkg/views/target/info/view.go b/pkg/views/target/info/view.go new file mode 100644 index 0000000000..96f709862a --- /dev/null +++ b/pkg/views/target/info/view.go @@ -0,0 +1,101 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package info + +import ( + "fmt" + "os" + + "github.com/charmbracelet/lipgloss" + "github.com/daytonaio/daytona/pkg/apiclient" + "github.com/daytonaio/daytona/pkg/views" + views_util "github.com/daytonaio/daytona/pkg/views/util" + "golang.org/x/term" +) + +const propertyNameWidth = 16 + +var propertyNameStyle = lipgloss.NewStyle(). + Foreground(views.LightGray) + +var propertyValueStyle = lipgloss.NewStyle(). + Foreground(views.Light). + Bold(true) + +func Render(target *apiclient.TargetDTO, forceUnstyled bool) { + var output string + nameLabel := "Name" + + output += "\n" + output += getInfoLine(nameLabel, target.Name) + "\n" + + output += getInfoLine("ID", target.Id) + "\n" + + providerLabel := target.TargetConfig.ProviderInfo.Name + if target.TargetConfig.ProviderInfo.Label != nil { + providerLabel = *target.TargetConfig.ProviderInfo.Label + } + + output += getInfoLine("Provider", providerLabel) + "\n" + + output += getInfoLine("Runner", target.TargetConfig.ProviderInfo.RunnerName) + "\n" + + if target.Default { + output += getInfoLine("Default", "Yes") + "\n" + } + + output += getInfoLineState("State", target.State, target.Metadata) + "\n" + if target.State.Error != nil { + output += getInfoLine("Error", *target.State.Error) + "\n" + } + + output += getInfoLine("# Workspaces", fmt.Sprint(len(target.Workspaces))) + "\n" + + if target.TargetConfig.Options != "" { + output += getInfoLine("Options", target.TargetConfig.Options) + "\n" + } + + if target.ProviderMetadata != nil && *target.ProviderMetadata != "" { + output += getInfoLine("Metadata", *target.ProviderMetadata) + "\n" + } + + terminalWidth, _, err := term.GetSize(int(os.Stdout.Fd())) + if err != nil { + fmt.Println(output) + return + } + if terminalWidth < views.TUITableMinimumWidth || forceUnstyled { + renderUnstyledInfo(output) + return + } + + renderTUIView(output, views.GetContainerBreakpointWidth(terminalWidth)) +} + +func renderUnstyledInfo(output string) { + fmt.Println(output) +} + +func renderTUIView(output string, width int) { + output = lipgloss.NewStyle().PaddingLeft(3).Render(output) + + content := lipgloss. + NewStyle().Width(width). + Render(output) + + fmt.Println(content) +} + +func getInfoLine(key, value string) string { + return propertyNameStyle.Render(fmt.Sprintf("%-*s", propertyNameWidth, key)) + propertyValueStyle.Render(value) + "\n" +} + +func getInfoLineState(key string, state apiclient.ResourceState, metadata *apiclient.TargetMetadata) string { + stateLabel := views.GetStateLabel(state.Name) + + if metadata != nil { + views_util.CheckAndAppendTimeLabel(&stateLabel, state, metadata.Uptime) + } + return propertyNameStyle.Render(fmt.Sprintf("%-*s", propertyNameWidth, key)) + stateLabel + propertyValueStyle.Foreground(views.Light).Render("\n") +} diff --git a/pkg/views/target/list/view.go b/pkg/views/target/list/view.go index 1d45ce2064..682f21696f 100644 --- a/pkg/views/target/list/view.go +++ b/pkg/views/target/list/view.go @@ -1,98 +1,125 @@ // Copyright 2024 Daytona Platforms Inc. // SPDX-License-Identifier: Apache-2.0 -package target +package list import ( "fmt" "sort" + "github.com/charmbracelet/lipgloss" + "github.com/daytonaio/daytona/internal/util" "github.com/daytonaio/daytona/pkg/apiclient" "github.com/daytonaio/daytona/pkg/views" - "github.com/daytonaio/daytona/pkg/views/util" + info_view "github.com/daytonaio/daytona/pkg/views/target/info" views_util "github.com/daytonaio/daytona/pkg/views/util" ) -type rowData struct { - Target string - Provider string - IsDefault string - Options string +type RowData struct { + Name string + Provider string + WorkspaceCount string + Default bool + Status string + TargetConfigProperty string + Uptime string } -func ListTargets(targetList []apiclient.ProviderTarget) { +func ListTargets(targetList []apiclient.TargetDTO, activeProfileName string, showOptions bool) { if len(targetList) == 0 { views_util.NotifyEmptyTargetList(true) return } - sortTargets(&targetList) + SortTargets(&targetList) - data := [][]string{} + targetConfigPropertyHeader := "Config Name" - for _, target := range targetList { - data = append(data, getRowFromRowData(&target)) + if showOptions { + targetConfigPropertyHeader = "Options" } - table := util.GetTableView(data, []string{ - "Target", "Provider", "Default", "Options", - }, nil, func() { - renderUnstyledList(targetList) - }) + headers := []string{"Target", targetConfigPropertyHeader, "# Workspaces", "Default", "Status"} - fmt.Println(table) -} + data := util.ArrayMap(targetList, func(target apiclient.TargetDTO) []string { + provider := target.TargetConfig.ProviderInfo.Name + if target.TargetConfig.ProviderInfo.Label != nil { + provider = *target.TargetConfig.ProviderInfo.Label + } -func getRowFromRowData(target *apiclient.ProviderTarget) []string { - var isDefault string - var data rowData + rowData := RowData{ + Name: target.Name, + Provider: provider, + TargetConfigProperty: target.TargetConfig.Name, + WorkspaceCount: fmt.Sprint(len(target.Workspaces)), + Default: target.Default, + Status: views.GetStateLabel(target.State.Name), + } - data.Target = target.Name - data.Provider = target.ProviderInfo.Name - data.Options = target.Options + if showOptions { + rowData.TargetConfigProperty = target.TargetConfig.Options + } - if target.IsDefault { - isDefault = views.ActiveStyle.Render("Yes") - } else { - isDefault = views.InactiveStyle.Render("/") - } + if target.Metadata != nil { + views_util.CheckAndAppendTimeLabel(&rowData.Status, target.State, target.Metadata.Uptime) + } - row := []string{ - views.NameStyle.Render(data.Target), - views.DefaultRowDataStyle.Render(data.Provider), - isDefault, - views.DefaultRowDataStyle.Render(data.Options), - } + return getRowFromRowData(rowData) + }) - return row -} + footer := lipgloss.NewStyle().Foreground(views.LightGray).Render(views.GetListFooter(activeProfileName, &views.Padding{})) -func sortTargets(targets *[]apiclient.ProviderTarget) { - sort.Slice(*targets, func(i, j int) bool { - t1 := (*targets)[i] - t2 := (*targets)[j] - return t1.ProviderInfo.Name < t2.ProviderInfo.Name + table := views_util.GetTableView(data, headers, &footer, func() { + renderUnstyledList(targetList) }) + + fmt.Println(table) } -func renderUnstyledList(targetList []apiclient.ProviderTarget) { - output := "\n" +func SortTargets(targetList *[]apiclient.TargetDTO) { + sort.Slice(*targetList, func(i, j int) bool { + // Sort the default target on top + if (*targetList)[i].Default && !(*targetList)[j].Default { + return true + } + if !(*targetList)[i].Default && (*targetList)[j].Default { + return false + } - for _, target := range targetList { - output += fmt.Sprintf("%s %s", views.GetPropertyKey("Target Name: "), target.Name) + "\n\n" + pi, pj := views_util.GetStateSortPriorities((*targetList)[i].State.Name, (*targetList)[j].State.Name) + if pi != pj { + return pi < pj + } - output += fmt.Sprintf("%s %s", views.GetPropertyKey("Target Provider: "), target.ProviderInfo.Name) + "\n\n" + // If two targets have the same state priority, compare the UpdatedAt property + return (*targetList)[i].State.UpdatedAt > (*targetList)[j].State.UpdatedAt + }) +} - if target.IsDefault { - output += fmt.Sprintf("%s %s", views.GetPropertyKey("Default: "), "Yes") + "\n\n" +func renderUnstyledList(targetList []apiclient.TargetDTO) { + for _, target := range targetList { + info_view.Render(&target, true) + + if target.Id != targetList[len(targetList)-1].Id { + fmt.Printf("\n%s\n\n", views.SeparatorString) } + } +} - output += fmt.Sprintf("%s %s", views.GetPropertyKey("Target Options: "), target.Options) + "\n\n" +func getRowFromRowData(rowData RowData) []string { + var isDefault string - if target.Name != targetList[len(targetList)-1].Name { - output += views.SeparatorString + "\n\n" - } + if rowData.Default { + isDefault = "Yes" + } else { + isDefault = "/" } - fmt.Println(output) + return []string{ + fmt.Sprintf("%s %s", views.NameStyle.Render(rowData.Name), views.DefaultRowDataStyle.Render(fmt.Sprintf("(%s)", rowData.Provider))), + views.DefaultRowDataStyle.Render(rowData.TargetConfigProperty), + views.DefaultRowDataStyle.Render(rowData.WorkspaceCount), + isDefault, + rowData.Status, + } } diff --git a/pkg/views/target/name.go b/pkg/views/target/name.go new file mode 100644 index 0000000000..bf1b4da023 --- /dev/null +++ b/pkg/views/target/name.go @@ -0,0 +1,38 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package target + +import ( + "errors" + "log" + + "github.com/charmbracelet/huh" + "github.com/daytonaio/daytona/pkg/views" +) + +func SetTargetNameView(name *string, existingNames []string) { + form := huh.NewForm( + huh.NewGroup( + huh.NewInput(). + Title("Target Name"). + Value(name). + Validate(func(str string) error { + if str == "" { + return errors.New("name can not be blank") + } + for _, existingName := range existingNames { + if existingName == str { + return errors.New("name already in use") + } + } + return nil + }), + ), + ).WithHeight(5).WithTheme(views.GetCustomTheme()) + + err := form.Run() + if err != nil { + log.Fatal(err) + } +} diff --git a/pkg/views/target/select.go b/pkg/views/target/select.go deleted file mode 100644 index d3f9a345b3..0000000000 --- a/pkg/views/target/select.go +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package target - -import ( - "fmt" - - "github.com/charmbracelet/bubbles/list" - tea "github.com/charmbracelet/bubbletea" - "github.com/daytonaio/daytona/internal/util" - "github.com/daytonaio/daytona/pkg/apiclient" - "github.com/daytonaio/daytona/pkg/common" - "github.com/daytonaio/daytona/pkg/views" - "github.com/daytonaio/daytona/pkg/views/provider" -) - -const NewTargetName = "+ New Target" - -type TargetView struct { - Name string - Options string - IsDefault bool - ProviderInfo ProviderInfo -} - -type ProviderInfo struct { - Name string - Version string - Installed *bool -} - -func GetTargetFromPrompt(targets []apiclient.ProviderTarget, activeProfileName string, providerViewList *[]provider.ProviderView, withNewTarget bool, actionVerb string) (*TargetView, error) { - items := util.ArrayMap(targets, func(t apiclient.ProviderTarget) list.Item { - return item{ - target: GetTargetViewFromTarget(t), - } - }) - - if withNewTarget { - name := NewTargetName - options := "{}" - items = append(items, item{ - target: TargetView{ - Name: name, - Options: options, - }, - }) - } - - // Display options for providers that are not installed - if providerViewList != nil { - for _, providerView := range *providerViewList { - if providerView.Installed != nil && *providerView.Installed { - continue - } - var label string - if providerView.Label != nil { - label = *providerView.Label - } else { - label = providerView.Name - } - - items = append(items, item{ - target: TargetView{ - Name: fmt.Sprintf("Add a %s Provider Target", label), - Options: "{}", - ProviderInfo: ProviderInfo{ - Name: providerView.Name, - Version: providerView.Version, - Installed: providerView.Installed, - }, - }, - }) - } - } - - l := views.GetStyledSelectList(items) - m := model{list: l} - m.list.Title = views.GetStyledMainTitle("Choose a Target To " + actionVerb) - m.footer = views.GetListFooter(activeProfileName, views.DefaultListFooterPadding) - - p, err := tea.NewProgram(m, tea.WithAltScreen()).Run() - if err != nil { - return nil, err - } - - if m, ok := p.(model); ok && m.choice != nil { - return m.choice, nil - } - - return nil, common.ErrCtrlCAbort -} - -func GetTargetViewFromTarget(target apiclient.ProviderTarget) TargetView { - return TargetView{ - Name: target.Name, - Options: target.Options, - IsDefault: target.IsDefault, - ProviderInfo: ProviderInfo{ - Name: target.ProviderInfo.Name, - Version: target.ProviderInfo.Version, - }, - } -} diff --git a/pkg/views/target/selection/target.go b/pkg/views/target/selection/target.go new file mode 100644 index 0000000000..919994e162 --- /dev/null +++ b/pkg/views/target/selection/target.go @@ -0,0 +1,142 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package selection + +import ( + "fmt" + "os" + + "github.com/charmbracelet/bubbles/list" + tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/lipgloss" + "github.com/daytonaio/daytona/pkg/apiclient" + "github.com/daytonaio/daytona/pkg/views" + list_view "github.com/daytonaio/daytona/pkg/views/target/list" + views_util "github.com/daytonaio/daytona/pkg/views/util" +) + +var NewTargetIdentifier = "" + +func generateTargetList(targets []apiclient.TargetDTO, isMultipleSelect bool, withNewTarget bool, action string) []list.Item { + // Initialize an empty list of items. + items := []list.Item{} + + // Populate items with titles and descriptions from targets. + for _, target := range targets { + var providerName string + + if target.TargetConfig.ProviderInfo.Label != nil { + providerName = *target.TargetConfig.ProviderInfo.Label + } else { + providerName = target.TargetConfig.ProviderInfo.Name + } + + stateLabel := views.GetStateLabel(target.State.Name) + + if target.Metadata != nil { + views_util.CheckAndAppendTimeLabel(&stateLabel, target.State, target.Metadata.Uptime) + } + + newItem := item[apiclient.TargetDTO]{ + title: target.Name, + id: target.Id, + desc: providerName, + state: stateLabel, + target: &target, + choiceProperty: target, + } + + if isMultipleSelect { + newItem.isMultipleSelect = true + newItem.action = action + } + + items = append(items, newItem) + } + + if withNewTarget { + items = append(items, item[apiclient.TargetDTO]{ + title: "+ Create a new target", + id: NewTargetIdentifier, + desc: "", + target: &apiclient.TargetDTO{Name: "+ Create a new target"}, + choiceProperty: apiclient.TargetDTO{Name: NewTargetIdentifier}, + }) + } + + return items +} + +func getTargetProgramEssentials(modelTitle string, withNewTarget bool, actionVerb string, targets []apiclient.TargetDTO, footerText string, isMultipleSelect bool) tea.Model { + + items := generateTargetList(targets, isMultipleSelect, withNewTarget, actionVerb) + + d := ItemDelegate[apiclient.TargetDTO]{} + + l := list.New(items, d, 0, 0) + + l.Styles.FilterPrompt = lipgloss.NewStyle().Foreground(views.Green) + l.Styles.FilterCursor = lipgloss.NewStyle().Foreground(views.Green) + + l.FilterInput.PromptStyle = lipgloss.NewStyle().Foreground(views.Green) + l.FilterInput.TextStyle = lipgloss.NewStyle().Foreground(views.Green) + + m := model[apiclient.TargetDTO]{list: l} + + m.list.Title = views.GetStyledMainTitle(modelTitle + actionVerb) + m.list.Styles.Title = lipgloss.NewStyle().Foreground(views.Green).Bold(true) + m.footer = footerText + + p, err := tea.NewProgram(m, tea.WithAltScreen()).Run() + + if err != nil { + fmt.Println("Error running program:", err) + os.Exit(1) + } + + return p +} + +func selectTargetPrompt(targets []apiclient.TargetDTO, withNewTarget bool, actionVerb string, choiceChan chan<- *apiclient.TargetDTO) { + list_view.SortTargets(&targets) + + p := getTargetProgramEssentials("Select a Target To ", withNewTarget, actionVerb, targets, "", false) + if m, ok := p.(model[apiclient.TargetDTO]); ok && m.choice != nil { + choiceChan <- m.choice + } else { + choiceChan <- nil + } +} + +func GetTargetFromPrompt(targets []apiclient.TargetDTO, withNewTarget bool, actionVerb string) *apiclient.TargetDTO { + choiceChan := make(chan *apiclient.TargetDTO) + + go selectTargetPrompt(targets, withNewTarget, actionVerb, choiceChan) + + return <-choiceChan +} + +func selectTargetsFromPrompt(targets []apiclient.TargetDTO, actionVerb string, choiceChan chan<- []*apiclient.TargetDTO) { + list_view.SortTargets(&targets) + + footerText := lipgloss.NewStyle().Bold(true).PaddingLeft(2).Render(fmt.Sprintf("\n\nPress 'x' to mark a target.\nPress 'enter' to %s the current/marked targets.", actionVerb)) + p := getTargetProgramEssentials("Select Targets To ", false, actionVerb, targets, footerText, true) + + m, ok := p.(model[apiclient.TargetDTO]) + if ok && m.choices != nil { + choiceChan <- m.choices + } else if ok && m.choice != nil { + choiceChan <- []*apiclient.TargetDTO{m.choice} + } else { + choiceChan <- nil + } +} + +func GetTargetsFromPrompt(targets []apiclient.TargetDTO, actionVerb string) []*apiclient.TargetDTO { + choiceChan := make(chan []*apiclient.TargetDTO) + + go selectTargetsFromPrompt(targets, actionVerb, choiceChan) + + return <-choiceChan +} diff --git a/pkg/views/target/selection/view.go b/pkg/views/target/selection/view.go new file mode 100644 index 0000000000..4edb39eb3f --- /dev/null +++ b/pkg/views/target/selection/view.go @@ -0,0 +1,239 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package selection + +import ( + "fmt" + "io" + "log" + "os" + "strings" + "time" + + "github.com/charmbracelet/bubbles/list" + tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/lipgloss" + "github.com/daytonaio/daytona/cmd/daytona/config" + "github.com/daytonaio/daytona/pkg/apiclient" + "github.com/daytonaio/daytona/pkg/views" + "golang.org/x/term" +) + +var selectedStyles = lipgloss.NewStyle(). + Border(lipgloss.NormalBorder(), false, false, false, true). + BorderForeground(views.Green). + Bold(true). + Padding(0, 0, 0, 1) + +var statusMessageGreenStyle = lipgloss.NewStyle().Bold(true). + Foreground(lipgloss.AdaptiveColor{Light: "#04B575", Dark: "#04B575"}). + Render + +var statusMessageDangerStyle = lipgloss.NewStyle().Bold(true). + Foreground(lipgloss.AdaptiveColor{Light: "#FF474C", Dark: "#FF474C"}). + Render + +type item[T any] struct { + id, title, desc, state string + target *apiclient.TargetDTO + choiceProperty T + isMarked bool + isMultipleSelect bool + action string +} + +func (i item[T]) Title() string { + title := i.title + + if i.target.Default { + title += " (default)" + } + + return title +} + +func (i item[T]) Id() string { return i.id } +func (i item[T]) Description() string { + desc := i.desc + if i.target.TargetConfig.ProviderInfo.RunnerName != "" { + desc = fmt.Sprintf("%s (%s)", desc, i.target.TargetConfig.ProviderInfo.RunnerName) + } + return desc +} +func (i item[T]) State() string { return i.state } +func (i item[T]) FilterValue() string { return i.title } + +type model[T any] struct { + list list.Model + choice *T + choices []*T + footer string + initialWidthSet bool +} + +func (m model[T]) Init() tea.Cmd { + return nil +} + +func (m model[T]) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + if !m.initialWidthSet { + _, _, err := term.GetSize(int(os.Stdout.Fd())) + if err != nil { + m.list.SetWidth(150) + } + } + + switch msg := msg.(type) { + case tea.KeyMsg: + switch keypress := msg.String(); keypress { + case "ctrl+c": + return m, tea.Quit + + case "enter": + i, ok := m.list.SelectedItem().(item[T]) + if ok { + m.choice = &i.choiceProperty + } + targetList := m.list.Items() + var choices []*T + for _, target := range targetList { + if target.(item[T]).isMarked { + targetItem, ok := target.(item[T]) + if !ok { + continue + } + choices = append(choices, &targetItem.choiceProperty) + } + + } + m.choices = choices + return m, tea.Quit + } + + case tea.WindowSizeMsg: + h, v := views.DocStyle.GetFrameSize() + m.list.SetSize(msg.Width-h, msg.Height-v) + } + + var cmd tea.Cmd + m.list, cmd = m.list.Update(msg) + return m, cmd +} + +func (m model[T]) View() string { + if m.footer == "" { + c, err := config.GetConfig() + if err != nil { + log.Fatal(err) + } + + activeProfile, err := c.GetActiveProfile() + if err != nil { + log.Fatal(err) + } + + m.footer = views.GetListFooter(activeProfile.Name, views.DefaultListFooterPadding) + } + + terminalWidth, terminalHeight, err := term.GetSize(int(os.Stdout.Fd())) + if err != nil { + return "" + } + + if m.list.FilterState() == list.Filtering { + return views.DocStyle.MaxWidth(terminalWidth - 4).MaxHeight(terminalHeight - 4).Render(m.list.View() + m.footer) + } + + return views.DocStyle.MaxWidth(terminalWidth - 4).Height(terminalHeight - 2).Render(m.list.View() + m.footer) +} + +type ItemDelegate[T any] struct { +} + +func (d ItemDelegate[T]) Render(w io.Writer, m list.Model, index int, listItem list.Item) { + i, _ := listItem.(item[T]) // Cast the listItem to your custom item type + s := strings.Builder{} + + var isSelected = index == m.Index() + + baseStyles := lipgloss.NewStyle().Padding(0, 0, 0, 2) + + title := baseStyles.Render(i.Title()) + idLabel := i.Id() + if i.Id() == NewTargetIdentifier { + idLabel = "" + } + id := baseStyles.Foreground(views.Gray).Render(idLabel) + description := baseStyles.Render(i.Description()) + + // Add the created/updated time if it's available + timeWidth := m.Width() - baseStyles.GetHorizontalFrameSize() - lipgloss.Width(title) + timeStyles := lipgloss.NewStyle(). + Align(lipgloss.Right). + Width(timeWidth) + stateLabel := timeStyles.Render("") + if i.State() != "" { + stateLabel = timeStyles.Render(i.State()) + } + + // Adjust styles as the user moves through the menu + if isSelected { + title = selectedStyles.Foreground(views.Green).Render(i.Title()) + id = selectedStyles.Foreground(views.Gray).Render(idLabel) + description = selectedStyles.Foreground(views.DimmedGreen).Render(i.Description()) + stateLabel = timeStyles.Foreground(views.DimmedGreen).Render(stateLabel) + } + + // Render to the terminal + s.WriteString(lipgloss.JoinHorizontal(lipgloss.Bottom, title, stateLabel)) + s.WriteRune('\n') + s.WriteString(id) + s.WriteRune('\n') + s.WriteString(description) + s.WriteRune('\n') + + fmt.Fprint(w, s.String()) +} + +func (d ItemDelegate[T]) Height() int { + height := lipgloss.NewStyle().GetVerticalFrameSize() + 4 + return height +} + +func (d ItemDelegate[T]) Spacing() int { + return 0 +} + +func (d ItemDelegate[T]) Update(msg tea.Msg, m *list.Model) tea.Cmd { + i, ok := m.SelectedItem().(item[T]) + if !ok { + return nil + } + + m.StatusMessageLifetime = time.Millisecond * 2000 + + var title string + switch msg := msg.(type) { + case tea.KeyMsg: + switch keypress := msg.String(); keypress { + case "x": + if !i.isMultipleSelect { + return nil + } + if i.isMarked { + i.title = strings.TrimPrefix(i.title, statusMessageDangerStyle(fmt.Sprintf("%s: ", i.action))) + i.isMarked = false + m.SetItem(m.Index(), i) + return m.NewStatusMessage(statusMessageGreenStyle("Removed target from list: ") + statusMessageGreenStyle(i.title)) + } + + title = i.title + i.title = statusMessageDangerStyle(fmt.Sprintf("%s: ", i.action)) + statusMessageGreenStyle(i.title) + i.isMarked = true + m.SetItem(m.Index(), i) + return m.NewStatusMessage(statusMessageDangerStyle("Added target to list: ") + statusMessageGreenStyle(title)) + } + } + return nil +} diff --git a/pkg/views/target/set.go b/pkg/views/targetconfig/create.go similarity index 74% rename from pkg/views/target/set.go rename to pkg/views/targetconfig/create.go index 4114143033..9a348b61a8 100644 --- a/pkg/views/target/set.go +++ b/pkg/views/targetconfig/create.go @@ -1,7 +1,7 @@ // Copyright 2024 Daytona Platforms Inc. // SPDX-License-Identifier: Apache-2.0 -package target +package targetconfig import ( "encoding/json" @@ -22,16 +22,16 @@ import ( "github.com/daytonaio/daytona/pkg/views" ) -func NewTargetNameInput(targetName *string, existingTargetNames []string) error { +func NewTargetConfigNameInput(name *string, existingNames []string) error { input := huh.NewInput(). - Title("Name"). - Value(targetName). + Title("Target Config Name"). + Value(name). Validate(func(s string) error { if s == "" { return errors.New("Name cannot be empty") } - if slices.Contains(existingTargetNames, s) { - return errors.New("Target with the same name already exists") + if slices.Contains(existingNames, s) { + return errors.New("Target config with the same name already exists") } return nil }) @@ -44,32 +44,36 @@ func NewTargetNameInput(targetName *string, existingTargetNames []string) error return nil } -func SetTargetForm(target *TargetView, targetManifest map[string]apiclient.ProviderProviderTargetProperty) error { - fields := make([]huh.Field, 0, len(targetManifest)) +func CreateTargetConfigForm(targetConfig *TargetConfigView, targetConfigManifest map[string]apiclient.TargetConfigProperty) error { + fields := make([]huh.Field, 0, len(targetConfigManifest)) groups := []*huh.Group{} options := make(map[string]interface{}) - err := json.Unmarshal([]byte(target.Options), &options) + err := json.Unmarshal([]byte(targetConfig.Options), &options) if err != nil { return err } - sortedKeys := make([]string, 0, len(targetManifest)) - for k := range targetManifest { + sortedKeys := make([]string, 0, len(targetConfigManifest)) + for k := range targetConfigManifest { sortedKeys = append(sortedKeys, k) } sort.Strings(sortedKeys) for _, name := range sortedKeys { - property := targetManifest[name] + property := targetConfigManifest[name] if property.DisabledPredicate != nil && *property.DisabledPredicate != "" { - if matched, err := regexp.Match(*property.DisabledPredicate, []byte(target.Name)); err == nil && matched { + if matched, err := regexp.Match(*property.DisabledPredicate, []byte(targetConfig.Name)); err == nil && matched { continue } } + if property.Type == nil { + continue + } + switch *property.Type { - case apiclient.ProviderTargetPropertyTypeFloat, apiclient.ProviderTargetPropertyTypeInt: + case apiclient.TargetConfigPropertyTypeFloat, apiclient.TargetConfigPropertyTypeInt: var initialValue *string floatValue, ok := options[name].(float64) if ok { @@ -80,7 +84,7 @@ func SetTargetForm(target *TargetView, targetManifest map[string]apiclient.Provi input, value := getInput(name, property, initialValue) fields = append(fields, input) options[name] = value - case apiclient.ProviderTargetPropertyTypeString: + case apiclient.TargetConfigPropertyTypeString: var initialValue *string v, ok := options[name].(string) if ok { @@ -90,7 +94,7 @@ func SetTargetForm(target *TargetView, targetManifest map[string]apiclient.Provi input, value := getInput(name, property, initialValue) fields = append(fields, input) options[name] = value - case apiclient.ProviderTargetPropertyTypeBoolean: + case apiclient.TargetConfigPropertyTypeBoolean: var initialValue *bool v, ok := options[name].(bool) if ok { @@ -100,7 +104,7 @@ func SetTargetForm(target *TargetView, targetManifest map[string]apiclient.Provi confirm, value := getConfirm(name, property, initialValue) fields = append(fields, confirm) options[name] = value - case apiclient.ProviderTargetPropertyTypeOption: + case apiclient.TargetConfigPropertyTypeOption: var initialValue *string v, ok := options[name].(string) if ok { @@ -110,7 +114,7 @@ func SetTargetForm(target *TargetView, targetManifest map[string]apiclient.Provi selectField, value := getSelect(name, property, initialValue) fields = append(fields, selectField) options[name] = value - case apiclient.ProviderTargetPropertyTypeFilePath: + case apiclient.TargetConfigPropertyTypeFilePath: var initialValue *string v, ok := options[name].(string) if ok { @@ -128,24 +132,29 @@ func SetTargetForm(target *TargetView, targetManifest map[string]apiclient.Provi return err } - for name, property := range targetManifest { + for name, property := range targetConfigManifest { if property.DisabledPredicate != nil && *property.DisabledPredicate != "" { - if matched, err := regexp.Match(*property.DisabledPredicate, []byte(target.Name)); err == nil && matched { + if matched, err := regexp.Match(*property.DisabledPredicate, []byte(targetConfig.Name)); err == nil && matched { continue } } + + if property.Type == nil { + continue + } + switch *property.Type { - case apiclient.ProviderTargetPropertyTypeInt: + case apiclient.TargetConfigPropertyTypeInt: options[name], err = strconv.Atoi(*options[name].(*string)) if err != nil { return err } - case apiclient.ProviderTargetPropertyTypeFloat: + case apiclient.TargetConfigPropertyTypeFloat: options[name], err = strconv.ParseFloat(*options[name].(*string), 64) if err != nil { return err } - case apiclient.ProviderTargetPropertyTypeFilePath: + case apiclient.TargetConfigPropertyTypeFilePath: if *options[name].(*string) == "none" { delete(options, name) } @@ -158,11 +167,11 @@ func SetTargetForm(target *TargetView, targetManifest map[string]apiclient.Provi } content := string(jsonContent) - target.Options = content + targetConfig.Options = content return nil } -func getInput(name string, property apiclient.ProviderProviderTargetProperty, initialValue *string) (*huh.Input, *string) { +func getInput(name string, property apiclient.TargetConfigProperty, initialValue *string) (*huh.Input, *string) { value := property.DefaultValue if initialValue != nil { value = initialValue @@ -173,11 +182,15 @@ func getInput(name string, property apiclient.ProviderProviderTargetProperty, in Description(*property.Description). Value(value). Validate(func(s string) error { + if property.Type == nil { + return errors.New("property type is not defined") + } + switch *property.Type { - case apiclient.ProviderTargetPropertyTypeInt: + case apiclient.TargetConfigPropertyTypeInt: _, err := strconv.Atoi(s) return err - case apiclient.ProviderTargetPropertyTypeFloat: + case apiclient.TargetConfigPropertyTypeFloat: _, err := strconv.ParseFloat(s, 64) return err } @@ -195,7 +208,7 @@ func getInput(name string, property apiclient.ProviderProviderTargetProperty, in return input, value } -func getSelect(name string, property apiclient.ProviderProviderTargetProperty, initialValue *string) (*huh.Select[string], *string) { +func getSelect(name string, property apiclient.TargetConfigProperty, initialValue *string) (*huh.Select[string], *string) { value := property.DefaultValue if initialValue != nil { value = initialValue @@ -210,7 +223,7 @@ func getSelect(name string, property apiclient.ProviderProviderTargetProperty, i Value(value), value } -func getConfirm(name string, property apiclient.ProviderProviderTargetProperty, initialValue *bool) (*huh.Confirm, *bool) { +func getConfirm(name string, property apiclient.TargetConfigProperty, initialValue *bool) (*huh.Confirm, *bool) { value := false if property.DefaultValue != nil && *property.DefaultValue == "true" { value = true @@ -225,7 +238,7 @@ func getConfirm(name string, property apiclient.ProviderProviderTargetProperty, Value(&value), &value } -func getFilePicker(name string, property apiclient.ProviderProviderTargetProperty, initialValue *string) ([]*huh.Group, *string) { +func getFilePicker(name string, property apiclient.TargetConfigProperty, initialValue *string) ([]*huh.Group, *string) { dirPath := "~" if property.DefaultValue != nil { diff --git a/pkg/views/targetconfig/list.go b/pkg/views/targetconfig/list.go new file mode 100644 index 0000000000..d4e8df5224 --- /dev/null +++ b/pkg/views/targetconfig/list.go @@ -0,0 +1,100 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package targetconfig + +import ( + "fmt" + "sort" + + "github.com/daytonaio/daytona/pkg/apiclient" + "github.com/daytonaio/daytona/pkg/views" + "github.com/daytonaio/daytona/pkg/views/util" +) + +type rowData struct { + ConfigName string + Provider string + RunnerName string + Options string +} + +func ListTargetConfigs(targetConfigs []apiclient.TargetConfig, showOptions bool) { + if len(targetConfigs) == 0 { + util.NotifyEmptyTargetConfigList(true) + return + } + + sortTargetConfigs(&targetConfigs) + + headers := []string{ + "Name", "Provider", "Runner", "Options", + } + data := [][]string{} + + for _, targetConfig := range targetConfigs { + data = append(data, getRowFromRowData(&targetConfig)) + } + + if !showOptions { + headers = headers[:len(headers)-1] + for value := range data { + data[value] = data[value][:len(data[value])-1] + } + } + + table := util.GetTableView(data, headers, nil, func() { + renderUnstyledList(targetConfigs) + }) + + fmt.Println(table) +} + +func getRowFromRowData(targetConfig *apiclient.TargetConfig) []string { + var data rowData + + data.ConfigName = targetConfig.Name + data.Provider = targetConfig.ProviderInfo.Name + data.RunnerName = targetConfig.ProviderInfo.RunnerName + if targetConfig.ProviderInfo.Label != nil { + data.Provider = *targetConfig.ProviderInfo.Label + } + data.Options = targetConfig.Options + + row := []string{ + views.NameStyle.Render(data.ConfigName), + views.DefaultRowDataStyle.Render(data.Provider), + views.DefaultRowDataStyle.Render(data.RunnerName), + views.DefaultRowDataStyle.Render(data.Options), + } + + return row +} + +func sortTargetConfigs(targetConfigs *[]apiclient.TargetConfig) { + sort.Slice(*targetConfigs, func(i, j int) bool { + t1 := (*targetConfigs)[i] + t2 := (*targetConfigs)[j] + return t1.ProviderInfo.Name < t2.ProviderInfo.Name + }) +} + +func renderUnstyledList(targetConfigs []apiclient.TargetConfig) { + output := "\n" + + for _, targetConfig := range targetConfigs { + output += fmt.Sprintf("%s %s", views.GetPropertyKey("Name: "), targetConfig.Name) + "\n\n" + + output += fmt.Sprintf("%s %s", views.GetPropertyKey("Provider: "), targetConfig.ProviderInfo.Name) + "\n\n" + + output += fmt.Sprintf("%s %s", views.GetPropertyKey("Runner: "), targetConfig.ProviderInfo.RunnerName) + "\n\n" + + output += fmt.Sprintf("%s %s", views.GetPropertyKey("Options: "), targetConfig.Options) + "\n\n" + + if targetConfig.Name != targetConfigs[len(targetConfigs)-1].Name { + output += views.SeparatorString + "\n\n" + } + } + + fmt.Println(output) +} diff --git a/pkg/views/targetconfig/select.go b/pkg/views/targetconfig/select.go new file mode 100644 index 0000000000..576ff0ea07 --- /dev/null +++ b/pkg/views/targetconfig/select.go @@ -0,0 +1,121 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package targetconfig + +import ( + "fmt" + + "github.com/charmbracelet/bubbles/list" + tea "github.com/charmbracelet/bubbletea" + "github.com/daytonaio/daytona/internal/util" + "github.com/daytonaio/daytona/pkg/apiclient" + "github.com/daytonaio/daytona/pkg/common" + "github.com/daytonaio/daytona/pkg/views" + "github.com/daytonaio/daytona/pkg/views/provider" +) + +const NewTargetConfigName = "+ New Target Config" + +type TargetConfigView struct { + Id string + Name string + RunnerName string + Options string + ProviderInfo ProviderInfo +} + +type ProviderInfo struct { + Name string + AgentlessTarget *bool + RunnerId string + RunnerName string + Version string + Label *string + Installed *bool + TargetConfigManifest map[string]apiclient.TargetConfigProperty +} + +func GetTargetConfigFromPrompt(targetConfigs []apiclient.TargetConfig, activeProfileName string, providerViewList *[]provider.ProviderView, withNewTargetConfig bool, actionVerb string) (*TargetConfigView, error) { + items := util.ArrayMap(targetConfigs, func(t apiclient.TargetConfig) list.Item { + return item{ + targetConfig: ToTargetConfigView(t), + } + }) + + if withNewTargetConfig { + name := NewTargetConfigName + options := "{}" + items = append(items, item{ + targetConfig: TargetConfigView{ + Name: name, + Options: options, + }, + }) + } + + // Display options for providers that are not installed + if providerViewList != nil { + for _, providerView := range *providerViewList { + if providerView.Installed != nil && *providerView.Installed { + continue + } + var label string + if providerView.Label != nil { + label = *providerView.Label + } else { + label = providerView.Name + } + + items = append(items, item{ + targetConfig: TargetConfigView{ + Name: fmt.Sprintf("Create a %s Target Config", label), + Options: "{}", + ProviderInfo: ProviderInfo{ + Name: providerView.Name, + RunnerId: providerView.RunnerId, + RunnerName: providerView.RunnerName, + Version: providerView.Version, + Label: providerView.Label, + Installed: providerView.Installed, + TargetConfigManifest: providerView.TargetConfigManifest, + AgentlessTarget: providerView.AgentlessTarget, + }, + }, + }) + } + } + + l := views.GetStyledSelectList(items) + m := model{list: l} + m.list.Title = views.GetStyledMainTitle("Choose a Target Config To " + actionVerb) + m.footer = views.GetListFooter(activeProfileName, views.DefaultListFooterPadding) + + p, err := tea.NewProgram(m, tea.WithAltScreen()).Run() + if err != nil { + return nil, err + } + + if m, ok := p.(model); ok && m.choice != nil { + return m.choice, nil + } + + return nil, common.ErrCtrlCAbort +} + +func ToTargetConfigView(targetConfig apiclient.TargetConfig) TargetConfigView { + return TargetConfigView{ + Id: targetConfig.Id, + Name: targetConfig.Name, + RunnerName: targetConfig.ProviderInfo.RunnerName, + Options: targetConfig.Options, + ProviderInfo: ProviderInfo{ + Name: targetConfig.ProviderInfo.Name, + AgentlessTarget: targetConfig.ProviderInfo.AgentlessTarget, + RunnerId: targetConfig.ProviderInfo.RunnerId, + RunnerName: targetConfig.ProviderInfo.RunnerName, + Version: targetConfig.ProviderInfo.Version, + Label: targetConfig.ProviderInfo.Label, + }, + } +} diff --git a/pkg/views/targetconfig/view.go b/pkg/views/targetconfig/view.go new file mode 100644 index 0000000000..874a3fc467 --- /dev/null +++ b/pkg/views/targetconfig/view.go @@ -0,0 +1,84 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package targetconfig + +import ( + "fmt" + "os" + + "github.com/charmbracelet/bubbles/list" + tea "github.com/charmbracelet/bubbletea" + "github.com/daytonaio/daytona/pkg/views" + "golang.org/x/term" +) + +type item struct { + targetConfig TargetConfigView +} + +func (i item) Title() string { return i.targetConfig.Name } + +func (i item) Description() string { + desc := i.targetConfig.ProviderInfo.Name + + if i.targetConfig.ProviderInfo.Label != nil { + desc = *i.targetConfig.ProviderInfo.Label + } + + if i.targetConfig.ProviderInfo.RunnerName != "" { + desc = fmt.Sprintf("%s (Runner %s)", desc, i.targetConfig.ProviderInfo.RunnerName) + } + + if i.targetConfig.ProviderInfo.Installed != nil { + if !*i.targetConfig.ProviderInfo.Installed { + desc += " (needs installing)" + } + } + + return desc +} +func (i item) FilterValue() string { return i.targetConfig.Name } + +type model struct { + list list.Model + choice *TargetConfigView + footer string +} + +func (m model) Init() tea.Cmd { + return nil +} + +func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + switch msg := msg.(type) { + case tea.KeyMsg: + switch keypress := msg.String(); keypress { + case "ctrl+c": + return m, tea.Quit + + case "enter": + i, ok := m.list.SelectedItem().(item) + if ok { + m.choice = &i.targetConfig + } + return m, tea.Quit + } + case tea.WindowSizeMsg: + h, v := views.DocStyle.GetFrameSize() + m.list.SetSize(msg.Width-h, msg.Height-v) + } + + var cmd tea.Cmd + m.list, cmd = m.list.Update(msg) + return m, cmd +} + +func (m model) View() string { + terminalWidth, terminalHeight, err := term.GetSize(int(os.Stdout.Fd())) + if err != nil { + return "" + } + + return views.DocStyle.Width(terminalWidth - 4).Height(terminalHeight - 4).Render(m.list.View() + m.footer) +} diff --git a/pkg/views/util/build_choice.go b/pkg/views/util/build_choice.go index fc786196d6..24de513dca 100644 --- a/pkg/views/util/build_choice.go +++ b/pkg/views/util/build_choice.go @@ -18,25 +18,26 @@ const ( NONE BuildChoice = "none" ) -type ProjectConfigDefaults struct { +type WorkspaceTemplateDefaults struct { BuildChoice BuildChoice Image *string ImageUser *string DevcontainerFilePath string + Labels map[string]string } -func GetProjectBuildChoice(project apiclient.CreateProjectDTO, defaults *ProjectConfigDefaults) (BuildChoice, string) { - if project.BuildConfig == nil { - if project.Image != nil && project.User != nil && +func GetWorkspaceBuildChoice(workspace apiclient.CreateWorkspaceDTO, defaults *WorkspaceTemplateDefaults) (BuildChoice, string) { + if workspace.BuildConfig == nil { + if workspace.Image != nil && workspace.User != nil && defaults.Image != nil && defaults.ImageUser != nil && - *project.Image == *defaults.Image && - *project.User == *defaults.ImageUser { + *workspace.Image == *defaults.Image && + *workspace.User == *defaults.ImageUser { return NONE, "None" } else { return CUSTOMIMAGE, "Custom Image" } } else { - if project.BuildConfig.Devcontainer != nil { + if workspace.BuildConfig.Devcontainer != nil { return DEVCONTAINER, "Devcontainer" } else { return AUTOMATIC, "Automatic" diff --git a/pkg/views/util/empty_list.go b/pkg/views/util/empty_list.go index 47ee648c78..c45f30b1b5 100644 --- a/pkg/views/util/empty_list.go +++ b/pkg/views/util/empty_list.go @@ -15,70 +15,70 @@ func NotifyEmptyProviderList(tip bool) { func NotifyEmptyGitProviderList(tip bool) { views.RenderInfoMessageBold("No Git providers found") if tip { - views.RenderTip("Use 'daytona git-provider add' to add a Git provider") + views.RenderTip("Use 'daytona git-provider create' to add a Git provider") } } -func NotifyEmptyTargetList(tip bool) { - views.RenderInfoMessageBold("No targets found") +func NotifyEmptyTargetConfigList(tip bool) { + views.RenderInfoMessageBold("No target configs found") if tip { - views.RenderTip("Use 'daytona target set' to add a target") + views.RenderTip("Use 'daytona target-config create' to create a target config") } } -func NotifyEmptyProjectConfigList(tip bool) { - views.RenderInfoMessageBold("No project configs found") +func NotifyEmptyWorkspaceTemplateList(tip bool) { + views.RenderInfoMessageBold("No workspace templates found") if tip { - views.RenderTip("Use 'daytona project-config add' to add a project config") + views.RenderTip("Use 'daytona template create' to add a workspace template") } } -func NotifyEmptyWorkspaceList(tip bool) { - views.RenderInfoMessageBold("No workspaces found") +func NotifyEmptyTargetList(tip bool) { + views.RenderInfoMessageBold("No targets found") if tip { - views.RenderTip("Use 'daytona create' to create a workspace") + views.RenderTip("Use 'daytona create' to create a target") } } -func NotifyEmptyContainerRegistryList(tip bool) { - views.RenderInfoMessageBold("No container registries found") +func NotifyEmptyWorkspaceList(tip bool) { + views.RenderInfoMessageBold("No workspaces found") if tip { - views.RenderTip("Use 'daytona container-registry add' to add a container registry") + views.RenderTip("Use 'daytona create' to create a workspace") } } func NotifyEmptyProfileList(tip bool) { views.RenderInfoMessageBold("No profiles found") if tip { - views.RenderTip("Use 'daytona profile add' to add a profile") + views.RenderTip("Use 'daytona profile create' to add a profile") } } func NotifyEmptyPrebuildList(tip bool) { views.RenderInfoMessageBold("No prebuilds found") if tip { - views.RenderTip("Use 'daytona prebuild add' to add a prebuild") + views.RenderTip("Use 'daytona prebuild create' to add a prebuild") } } func NotifyEmptyApiKeyList(tip bool) { views.RenderInfoMessageBold("No API keys found") if tip { - views.RenderTip("Use 'daytona api-key new' to create an API key") + views.RenderTip("Use 'daytona api-key create' to create an API key") } } func NotifyEmptyBuildList(tip bool) { views.RenderInfoMessageBold("No builds found") if tip { - views.RenderTip("Use 'daytona build run' to run a build or 'daytona prebuild add' to configure a prebuild rule") + views.RenderTip("Use 'daytona build run' to run a build or 'daytona prebuild create' to configure a prebuild rule") } } func NotifyEmptyEnvVarList(tip bool) { - views.RenderInfoMessageBold("No environment variables found") + views.RenderInfoMessageBold("No server environment variables found") if tip { - views.RenderTip("Use 'daytona env set' to set environment variables") + views.RenderTip("Use 'daytona env set' to add new server environment variables") } } @@ -88,3 +88,10 @@ func NotifyEmptyServerLogList(tip bool) { views.RenderTip("Use 'daytona serve' in order to create server log files") } } + +func NotifyEmptyRunnerList(tip bool) { + views.RenderInfoMessageBold("No runners found") + if tip { + views.RenderTip("Use 'daytona runner create' to register a runner") + } +} diff --git a/pkg/views/util/help.go b/pkg/views/util/help.go index 5de8f42ad0..bee2ef304f 100644 --- a/pkg/views/util/help.go +++ b/pkg/views/util/help.go @@ -38,8 +38,8 @@ func getLongDescriptionText() string { response += "\n" + fmt.Sprintf(" \x1b[1m%s\x1b[0m%s\n\n", "Daytona", " - your Dev Environment Manager") + " Use the following commands to get started:\n\n" + fmt.Sprintf(" \x1b[1m%-*s\x1b[0m%s", helpDescriptionLabelWidth, "1) daytona server", "Start the Daytona Server process locally\n") + - fmt.Sprintf(" \x1b[1m%-*s\x1b[0m%s", helpDescriptionLabelWidth, "2) daytona git-providers add", "Register a Git provider of your choice\n") + - fmt.Sprintf(" \x1b[1m%-*s\x1b[0m%s", helpDescriptionLabelWidth, "3) daytona target set", "Set a target to spin up your Dev Environments on\n") + + fmt.Sprintf(" \x1b[1m%-*s\x1b[0m%s", helpDescriptionLabelWidth, "2) daytona git-providers create", "Register a Git provider of your choice\n") + + fmt.Sprintf(" \x1b[1m%-*s\x1b[0m%s", helpDescriptionLabelWidth, "3) daytona target-config create", "Set a target config to spin up your Dev Environments on\n") + fmt.Sprintf(" \x1b[1m%-*s\x1b[0m%s", helpDescriptionLabelWidth, "4) daytona ide", "Choose the default IDE\n") + fmt.Sprintf(" \x1b[1m%-*s\x1b[0m%s", helpDescriptionLabelWidth, "5) daytona whoami", "Show information about the currently logged in user\n") + fmt.Sprintf(" \n%s\x1b[1m%s\x1b[0m\n\n", "That's it! Start coding - ", "daytona create") @@ -57,8 +57,8 @@ func getLongDescriptionFull() string { fmt.Sprintf("%sUse the following commands to get started:\n", " @@@@@@@@@@@@@@@@@@@@ ") + fmt.Sprintf("%s\n", " @@@@ @@ @@@@@@@@@@@ ") + fmt.Sprintf("%s\x1b[1m%-*s\x1b[0m%s", " @@@@@@@@ @@@ ", helpDescriptionLabelWidthWithSigil, "1) daytona server", "Start the Daytona Server process locally\n") + - fmt.Sprintf("%s\x1b[1m%-*s\x1b[0m%s", " @@@@@ @@@@@ ", helpDescriptionLabelWidthWithSigil, "2) daytona git-providers add", "Register a Git provider of your choice\n") + - fmt.Sprintf("%s\x1b[1m%-*s\x1b[0m%s", " @@@@@ @@@@@@@@ ", helpDescriptionLabelWidthWithSigil, "3) daytona target set", "Set a target to spin up your Dev Environments\n") + + fmt.Sprintf("%s\x1b[1m%-*s\x1b[0m%s", " @@@@@ @@@@@ ", helpDescriptionLabelWidthWithSigil, "2) daytona git-providers create", "Register a Git provider of your choice\n") + + fmt.Sprintf("%s\x1b[1m%-*s\x1b[0m%s", " @@@@@ @@@@@@@@ ", helpDescriptionLabelWidthWithSigil, "3) daytona target-config create", "Set a target config to spin up your Dev Environments\n") + fmt.Sprintf("%s\x1b[1m%-*s\x1b[0m%s", " @@@ @@@@@@@@@ ", helpDescriptionLabelWidthWithSigil, "4) daytona ide", "Choose the default IDE\n") + fmt.Sprintf("%s\x1b[1m%-*s\x1b[0m%s", " @@@@@@@@@ @@@@@@@@ @@ ", helpDescriptionLabelWidthWithSigil, "5) daytona whoami", "Show information about the currently logged in user\n") + fmt.Sprintf("%s\n", " @@@@@@@@@@@@@@@@@@ ") + diff --git a/pkg/views/util/state_sort.go b/pkg/views/util/state_sort.go new file mode 100644 index 0000000000..9bfbd43203 --- /dev/null +++ b/pkg/views/util/state_sort.go @@ -0,0 +1,22 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package util + +import ( + "github.com/daytonaio/daytona/pkg/apiclient" + "github.com/daytonaio/daytona/pkg/views" +) + +func GetStateSortPriorities(state1, state2 apiclient.ModelsResourceStateName) (int, int) { + pi, ok := views.ResourceListStatePriorities[state1] + if !ok { + pi = 99 + } + pj, ok2 := views.ResourceListStatePriorities[state2] + if !ok2 { + pj = 99 + } + + return pi, pj +} diff --git a/pkg/views/util/state_time.go b/pkg/views/util/state_time.go new file mode 100644 index 0000000000..b9779590df --- /dev/null +++ b/pkg/views/util/state_time.go @@ -0,0 +1,19 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package util + +import ( + "fmt" + + "github.com/daytonaio/daytona/internal/util" + "github.com/daytonaio/daytona/pkg/apiclient" +) + +func CheckAndAppendTimeLabel(stateLabel *string, state apiclient.ResourceState, uptime int32) { + if state.Name == apiclient.ResourceStateNameStarted && uptime != 0 { + *stateLabel = fmt.Sprintf("%s (%s)", *stateLabel, util.FormatUptime(uptime)) + } else if state.Name == apiclient.ResourceStateNameStopped || state.Name == apiclient.ResourceStateNameUnresponsive || state.Name == apiclient.ResourceStateNameError { + *stateLabel = fmt.Sprintf("%s (%s)", *stateLabel, util.FormatTimestamp(state.UpdatedAt)) + } +} diff --git a/pkg/views/util/table.go b/pkg/views/util/table.go index fdff0c49f2..6456d5dd60 100644 --- a/pkg/views/util/table.go +++ b/pkg/views/util/table.go @@ -7,6 +7,7 @@ import ( "fmt" "os" "regexp" + "strings" "github.com/charmbracelet/lipgloss" "github.com/charmbracelet/lipgloss/table" @@ -16,7 +17,7 @@ import ( var AdditionalPropertyPadding = " " -// Left border, BaseTableStyle padding left, additional padding for workspace name and target, BaseTableStyle padding right, BaseCellStyle padding right, right border +// Left border, BaseTableStyle padding left, additional padding for target name and target config, BaseTableStyle padding right, BaseCellStyle padding right, right border var RowWhiteSpace = 1 + 4 + len(AdditionalPropertyPadding)*2 + 4 + 4 + 1 var ArbitrarySpace = 10 @@ -68,7 +69,7 @@ func getMinimumWidth(data [][]string) int { // Remove ANSI escape codes regex := regexp.MustCompile("\x1b\\[[0-9;]*[a-zA-Z]") strippedCell := regex.ReplaceAllString(cell, "") - width += len(strippedCell) + width += longestLineLength(strippedCell) if width > widestRow { widestRow = width } @@ -77,3 +78,17 @@ func getMinimumWidth(data [][]string) int { } return widestRow } + +// Returns the length of the longest line in a string +func longestLineLength(input string) int { + lines := strings.Split(input, "\n") + maxLength := 0 + + for _, line := range lines { + if len(line) > maxLength { + maxLength = len(line) + } + } + + return maxLength +} diff --git a/pkg/views/util/validators.go b/pkg/views/util/validators.go new file mode 100644 index 0000000000..b2a7e20e79 --- /dev/null +++ b/pkg/views/util/validators.go @@ -0,0 +1,62 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package util + +import ( + "errors" + "strconv" + + "github.com/daytonaio/daytona/pkg/apiclient" +) + +func CreateServerPortValidator(config *apiclient.ServerConfig, portView *string, port *int32) func(string) error { + return func(string) error { + validatePort, err := strconv.Atoi(*portView) + if err != nil { + return errors.New("failed to parse port") + } + if validatePort < 0 || validatePort > 65535 { + return errors.New("port out of range") + } + *port = int32(validatePort) + + if config.ApiPort == config.HeadscalePort { + return errors.New("port conflict") + } + + return nil + } +} + +func CreatePortValidator(portView *string, port *int32) func(string) error { + return func(string) error { + validatePort, err := strconv.Atoi(*portView) + if err != nil { + return errors.New("failed to parse port") + } + if validatePort < 0 || validatePort > 65535 { + return errors.New("port out of range") + } + *port = int32(validatePort) + + return nil + } +} + +func CreateIntValidator(viewValue *string, value *int32) func(string) error { + return func(string) error { + validateInt, err := strconv.Atoi(*viewValue) + if err != nil { + return errors.New("failed to parse int") + } + + if validateInt <= 0 { + return errors.New("int out of range") + } + + *value = int32(validateInt) + + return nil + } +} diff --git a/pkg/views/workspace/create/configuration.go b/pkg/views/workspace/create/configuration.go index 946b213020..acd8fd087e 100644 --- a/pkg/views/workspace/create/configuration.go +++ b/pkg/views/workspace/create/configuration.go @@ -5,7 +5,6 @@ package create import ( "errors" - "log" "path/filepath" "github.com/charmbracelet/bubbles/key" @@ -15,17 +14,18 @@ import ( "github.com/daytonaio/daytona/pkg/apiclient" "github.com/daytonaio/daytona/pkg/common" "github.com/daytonaio/daytona/pkg/views" + "github.com/daytonaio/daytona/pkg/views/selection" views_util "github.com/daytonaio/daytona/pkg/views/util" - "github.com/daytonaio/daytona/pkg/views/workspace/selection" ) const ( DEVCONTAINER_FILEPATH = ".devcontainer/devcontainer.json" ) -var configurationHelpLine = lipgloss.NewStyle().Foreground(views.Gray).Render("enter: next f10: advanced configuration") +var configurationHelpLine = lipgloss.NewStyle().Foreground(views.Gray).Render("enter: next f10: configuration screen") -type ProjectConfigurationData struct { +type WorkspaceConfigurationData struct { + Name string BuildChoice string DevcontainerFilePath string Image string @@ -33,8 +33,9 @@ type ProjectConfigurationData struct { EnvVars map[string]string } -func NewConfigurationData(buildChoice views_util.BuildChoice, devContainerFilePath string, currentProject *apiclient.CreateProjectDTO, defaults *views_util.ProjectConfigDefaults) *ProjectConfigurationData { - projectConfigurationData := &ProjectConfigurationData{ +func NewConfigurationData(buildChoice views_util.BuildChoice, devContainerFilePath string, currentWorkspace *apiclient.CreateWorkspaceDTO, defaults *views_util.WorkspaceTemplateDefaults) *WorkspaceConfigurationData { + workspaceConfigurationData := &WorkspaceConfigurationData{ + Name: currentWorkspace.Name, BuildChoice: string(buildChoice), DevcontainerFilePath: defaults.DevcontainerFilePath, Image: *defaults.Image, @@ -42,103 +43,106 @@ func NewConfigurationData(buildChoice views_util.BuildChoice, devContainerFilePa EnvVars: map[string]string{}, } - if currentProject.Image != nil { - projectConfigurationData.Image = *currentProject.Image + if currentWorkspace.Image != nil { + workspaceConfigurationData.Image = *currentWorkspace.Image } - if currentProject.User != nil { - projectConfigurationData.User = *currentProject.User + if currentWorkspace.User != nil { + workspaceConfigurationData.User = *currentWorkspace.User } - if currentProject.EnvVars != nil { - projectConfigurationData.EnvVars = currentProject.EnvVars + if currentWorkspace.EnvVars != nil { + workspaceConfigurationData.EnvVars = currentWorkspace.EnvVars } - return projectConfigurationData + return workspaceConfigurationData } -func RunProjectConfiguration(projectList *[]apiclient.CreateProjectDTO, defaults views_util.ProjectConfigDefaults, isConfigImport bool) (bool, error) { - var currentProject *apiclient.CreateProjectDTO +func RunWorkspaceConfiguration(workspaceList *[]apiclient.CreateWorkspaceDTO, defaults views_util.WorkspaceTemplateDefaults, isTemplateImport bool) (bool, error) { + var currentWorkspace *apiclient.CreateWorkspaceDTO - if len(*projectList) > 1 { - currentProject = selection.GetProjectRequestFromPrompt(projectList) - if currentProject == nil { + if len(*workspaceList) > 1 { + currentWorkspace = selection.GetWorkspaceRequestFromPrompt(workspaceList) + if currentWorkspace == nil { return false, common.ErrCtrlCAbort } } else { - currentProject = &((*projectList)[0]) + currentWorkspace = &((*workspaceList)[0]) } - if currentProject.Name == selection.DoneConfiguring.Name { + if currentWorkspace.Name == selection.DoneConfiguring.Name { return false, nil } devContainerFilePath := defaults.DevcontainerFilePath builderChoice := views_util.AUTOMATIC - if currentProject.BuildConfig != nil { - if currentProject.BuildConfig.Devcontainer != nil { + if currentWorkspace.BuildConfig != nil { + if currentWorkspace.BuildConfig.Devcontainer != nil { builderChoice = views_util.DEVCONTAINER - devContainerFilePath = currentProject.BuildConfig.Devcontainer.FilePath + devContainerFilePath = currentWorkspace.BuildConfig.Devcontainer.FilePath } } else { - if currentProject.Image == nil && currentProject.User == nil || - *currentProject.Image == *defaults.Image && *currentProject.User == *defaults.ImageUser { + if currentWorkspace.Image == nil && currentWorkspace.User == nil || + *currentWorkspace.Image == *defaults.Image && *currentWorkspace.User == *defaults.ImageUser { builderChoice = views_util.NONE } else { builderChoice = views_util.CUSTOMIMAGE } } - projectConfigurationData := NewConfigurationData(builderChoice, devContainerFilePath, currentProject, &defaults) + workspaceConfigurationData := NewConfigurationData(builderChoice, devContainerFilePath, currentWorkspace, &defaults) - if !isConfigImport { - form := GetProjectConfigurationForm(projectConfigurationData) + if !isTemplateImport { + form := GetWorkspaceConfigurationForm(workspaceConfigurationData) err := form.WithProgramOptions(tea.WithAltScreen()).Run() if err != nil { - log.Fatal(err) + return false, err } } - for i := range *projectList { - if (*projectList)[i].Name == currentProject.Name { - if projectConfigurationData.BuildChoice == string(views_util.NONE) { - (*projectList)[i].BuildConfig = nil - (*projectList)[i].Image = defaults.Image - (*projectList)[i].User = defaults.ImageUser - } + for i := range *workspaceList { + if (*workspaceList)[i].Id != currentWorkspace.Id { + continue + } - if projectConfigurationData.BuildChoice == string(views_util.CUSTOMIMAGE) { - (*projectList)[i].BuildConfig = nil - (*projectList)[i].Image = &projectConfigurationData.Image - (*projectList)[i].User = &projectConfigurationData.User - } + if workspaceConfigurationData.BuildChoice == string(views_util.NONE) { + (*workspaceList)[i].BuildConfig = nil + (*workspaceList)[i].Image = defaults.Image + (*workspaceList)[i].User = defaults.ImageUser + } - if projectConfigurationData.BuildChoice == string(views_util.AUTOMATIC) { - (*projectList)[i].BuildConfig = &apiclient.BuildConfig{} - (*projectList)[i].Image = defaults.Image - (*projectList)[i].User = defaults.ImageUser - } + if workspaceConfigurationData.BuildChoice == string(views_util.CUSTOMIMAGE) { + (*workspaceList)[i].BuildConfig = nil + (*workspaceList)[i].Image = &workspaceConfigurationData.Image + (*workspaceList)[i].User = &workspaceConfigurationData.User + } - if projectConfigurationData.BuildChoice == string(views_util.DEVCONTAINER) { - (*projectList)[i].BuildConfig = &apiclient.BuildConfig{ - Devcontainer: &apiclient.DevcontainerConfig{ - FilePath: projectConfigurationData.DevcontainerFilePath, - }, - } - (*projectList)[i].Image = nil - (*projectList)[i].User = nil - } + if workspaceConfigurationData.BuildChoice == string(views_util.AUTOMATIC) { + (*workspaceList)[i].BuildConfig = &apiclient.BuildConfig{} + (*workspaceList)[i].Image = defaults.Image + (*workspaceList)[i].User = defaults.ImageUser + } - (*projectList)[i].EnvVars = projectConfigurationData.EnvVars + if workspaceConfigurationData.BuildChoice == string(views_util.DEVCONTAINER) { + (*workspaceList)[i].BuildConfig = &apiclient.BuildConfig{ + Devcontainer: &apiclient.DevcontainerConfig{ + FilePath: workspaceConfigurationData.DevcontainerFilePath, + }, + } + (*workspaceList)[i].Image = nil + (*workspaceList)[i].User = nil } + + (*workspaceList)[i].Name = workspaceConfigurationData.Name + (*workspaceList)[i].EnvVars = workspaceConfigurationData.EnvVars } - if len(*projectList) == 1 { + if len(*workspaceList) == 1 { return true, nil } - return RunProjectConfiguration(projectList, defaults, isConfigImport) + return RunWorkspaceConfiguration(workspaceList, defaults, isTemplateImport) } func validateDevcontainerFilename(filename string) error { @@ -149,7 +153,7 @@ func validateDevcontainerFilename(filename string) error { return nil } -func GetProjectConfigurationForm(projectConfiguration *ProjectConfigurationData) *huh.Form { +func GetWorkspaceConfigurationForm(workspaceConfiguration *WorkspaceConfigurationData) *huh.Form { buildOptions := []huh.Option[string]{ {Key: "Automatic", Value: string(views_util.AUTOMATIC)}, {Key: "Devcontainer", Value: string(views_util.DEVCONTAINER)}, @@ -158,33 +162,38 @@ func GetProjectConfigurationForm(projectConfiguration *ProjectConfigurationData) } form := huh.NewForm( + huh.NewGroup( + huh.NewInput(). + Title("Name"). + Value(&workspaceConfiguration.Name), + ), huh.NewGroup( huh.NewSelect[string](). Title("Choose a build configuration"). Options( buildOptions..., ). - Value(&projectConfiguration.BuildChoice), + Value(&workspaceConfiguration.BuildChoice), ).WithHeight(8), huh.NewGroup( huh.NewInput(). Title("Custom container image"). - Value(&projectConfiguration.Image), + Value(&workspaceConfiguration.Image), huh.NewInput(). Title("Container user"). - Value(&projectConfiguration.User), + Value(&workspaceConfiguration.User), ).WithHeight(5).WithHideFunc(func() bool { - return projectConfiguration.BuildChoice != string(views_util.CUSTOMIMAGE) + return workspaceConfiguration.BuildChoice != string(views_util.CUSTOMIMAGE) }), huh.NewGroup( huh.NewInput(). Title("Devcontainer file path"). - Value(&projectConfiguration.DevcontainerFilePath).Validate(validateDevcontainerFilename), + Value(&workspaceConfiguration.DevcontainerFilePath).Validate(validateDevcontainerFilename), ).WithHeight(5).WithHideFunc(func() bool { - return projectConfiguration.BuildChoice != string(views_util.DEVCONTAINER) + return workspaceConfiguration.BuildChoice != string(views_util.DEVCONTAINER) }), huh.NewGroup( - views.GetEnvVarsInput(&projectConfiguration.EnvVars), + views.GetEnvVarsInput(&workspaceConfiguration.EnvVars), ).WithHeight(12), ).WithTheme(views.GetCustomTheme()) diff --git a/pkg/views/workspace/create/summary.go b/pkg/views/workspace/create/summary.go index 8627636711..d5c692682f 100644 --- a/pkg/views/workspace/create/summary.go +++ b/pkg/views/workspace/create/summary.go @@ -12,53 +12,56 @@ import ( tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/huh" "github.com/charmbracelet/lipgloss" - util "github.com/daytonaio/daytona/internal/util" + "github.com/daytonaio/daytona/internal/util" "github.com/daytonaio/daytona/pkg/apiclient" "github.com/daytonaio/daytona/pkg/views" views_util "github.com/daytonaio/daytona/pkg/views/util" ) -type ProjectDetail string +type WorkspaceDetail string const ( - Build ProjectDetail = "Build" - DevcontainerConfig ProjectDetail = "Devcontainer Config" - Image ProjectDetail = "Image" - User ProjectDetail = "User" - EnvVars ProjectDetail = "Env Vars" - EMPTY_STRING = "" - DEFAULT_PADDING = 21 + Repository WorkspaceDetail = "Repository" + Branch WorkspaceDetail = "Branch" + Build WorkspaceDetail = "Build" + DevcontainerConfig WorkspaceDetail = "Devcontainer Config" + Image WorkspaceDetail = "Image" + User WorkspaceDetail = "User" + EnvVars WorkspaceDetail = "Env Vars" + EMPTY_STRING = "" + DEFAULT_PADDING = 21 ) type SummaryModel struct { - lg *lipgloss.Renderer - styles *Styles - form *huh.Form - width int - quitting bool - name string - projectList []apiclient.CreateProjectDTO - defaults *views_util.ProjectConfigDefaults - nameLabel string + lg *lipgloss.Renderer + styles *Styles + form *huh.Form + width int + quitting bool + name string + workspaceList []apiclient.CreateWorkspaceDTO + defaults *views_util.WorkspaceTemplateDefaults + nameLabel string } -type SubmissionFormConfig struct { - ChosenName *string - SuggestedName string - ExistingNames []string - ProjectList *[]apiclient.CreateProjectDTO - NameLabel string - Defaults *views_util.ProjectConfigDefaults +type SubmissionFormParams struct { + ChosenName *string + SuggestedName string + WorkspaceList *[]apiclient.CreateWorkspaceDTO + NameLabel string + Defaults *views_util.WorkspaceTemplateDefaults + ExistingWorkspaceNames []string + ImportConfirmation *bool } -var configureCheck bool +var doneCheck bool var userCancelled bool -var ProjectsConfigurationChanged bool +var WorkspacesConfigurationChanged bool -func RunSubmissionForm(config SubmissionFormConfig, pcImport *bool) error { - configureCheck = false +func RunSubmissionForm(params SubmissionFormParams) error { + doneCheck = true - m := NewSummaryModel(config, pcImport) + m := NewSummaryModel(params) if _, err := tea.NewProgram(m, tea.WithAltScreen()).Run(); err != nil { return err @@ -68,43 +71,48 @@ func RunSubmissionForm(config SubmissionFormConfig, pcImport *bool) error { return errors.New("user cancelled") } - if !configureCheck { + if doneCheck { return nil } - if config.Defaults.Image == nil || config.Defaults.ImageUser == nil { - return errors.New("default project entries are not set") + if params.Defaults.Image == nil || params.Defaults.ImageUser == nil { + return errors.New("default workspace entries are not set") } var err error - ProjectsConfigurationChanged, err = RunProjectConfiguration(config.ProjectList, *config.Defaults, *pcImport) + importConfirmation := false + if params.ImportConfirmation != nil { + importConfirmation = *params.ImportConfirmation + } + + WorkspacesConfigurationChanged, err = RunWorkspaceConfiguration(params.WorkspaceList, *params.Defaults, importConfirmation) if err != nil { return err } - return RunSubmissionForm(config, pcImport) + return RunSubmissionForm(params) } -func RenderSummary(name string, projectList []apiclient.CreateProjectDTO, defaults *views_util.ProjectConfigDefaults, nameLabel string) (string, error) { +func RenderSummary(name string, workspaceList []apiclient.CreateWorkspaceDTO, defaults *views_util.WorkspaceTemplateDefaults, nameLabel string) (string, error) { var output string - if name == "" { + if nameLabel == "" { output = views.GetStyledMainTitle("SUMMARY") } else { - output = views.GetStyledMainTitle(fmt.Sprintf("SUMMARY - %s %s", nameLabel, name)) + output = views.GetStyledMainTitle(fmt.Sprintf("SUMMARY - %s", nameLabel)) } output += "\n\n" - for i := range projectList { - if len(projectList) == 1 { - output += fmt.Sprintf("%s - %s\n", lipgloss.NewStyle().Foreground(views.Green).Render("Project"), (projectList[i].Source.Repository.Url)) + for i := range workspaceList { + if len(workspaceList) == 1 { + output += fmt.Sprintf("%s - %s\n", lipgloss.NewStyle().Foreground(views.Green).Render("Workspace"), (workspaceList[i].Name)) } else { - output += fmt.Sprintf("%s - %s\n", lipgloss.NewStyle().Foreground(views.Green).Render(fmt.Sprintf("%s #%d", "Project", i+1)), (projectList[i].Source.Repository.Url)) + output += fmt.Sprintf("%s - %s\n", lipgloss.NewStyle().Foreground(views.Green).Render(fmt.Sprintf("%s #%d", "Workspace", i+1)), (workspaceList[i].Name)) } - projectBuildChoice, choiceName := views_util.GetProjectBuildChoice(projectList[i], defaults) - output += renderProjectDetails(projectList[i], projectBuildChoice, choiceName) - if i < len(projectList)-1 { + workspaceBuildChoice, choiceName := views_util.GetWorkspaceBuildChoice(workspaceList[i], defaults) + output += renderWorkspaceDetails(workspaceList[i], workspaceBuildChoice, choiceName) + if i < len(workspaceList)-1 { output += "\n\n" } } @@ -112,82 +120,83 @@ func RenderSummary(name string, projectList []apiclient.CreateProjectDTO, defaul return output, nil } -func renderProjectDetails(project apiclient.CreateProjectDTO, buildChoice views_util.BuildChoice, choiceName string) string { - output := projectDetailOutput(Build, choiceName) +func renderWorkspaceDetails(workspace apiclient.CreateWorkspaceDTO, buildChoice views_util.BuildChoice, choiceName string) string { + output := workspaceDetailOutput(Repository, workspace.Source.Repository.Url) + "\n" + output += workspaceDetailOutput(Branch, workspace.Source.Repository.Branch) + "\n" + output += workspaceDetailOutput(Build, choiceName) if buildChoice == views_util.DEVCONTAINER { - if project.BuildConfig != nil { - if project.BuildConfig.Devcontainer != nil { + if workspace.BuildConfig != nil { + if workspace.BuildConfig.Devcontainer != nil { output += "\n" - output += projectDetailOutput(DevcontainerConfig, project.BuildConfig.Devcontainer.FilePath) + output += workspaceDetailOutput(DevcontainerConfig, workspace.BuildConfig.Devcontainer.FilePath) } } } else { - if project.Image != nil { + if workspace.Image != nil { if output != "" { output += "\n" } - output += projectDetailOutput(Image, *project.Image) + output += workspaceDetailOutput(Image, *workspace.Image) } - if project.User != nil { + if workspace.User != nil { if output != "" { output += "\n" } - output += projectDetailOutput(User, *project.User) + output += workspaceDetailOutput(User, *workspace.User) } } - if len(project.EnvVars) > 0 { + if len(workspace.EnvVars) > 0 { if output != "" { output += "\n" } var envVars string - for key, val := range project.EnvVars { + for key, val := range workspace.EnvVars { envVars += fmt.Sprintf("%s=%s; ", key, val) } - output += projectDetailOutput(EnvVars, strings.TrimSuffix(envVars, "; ")) + output += workspaceDetailOutput(EnvVars, strings.TrimSuffix(envVars, "; ")) } return output } -func projectDetailOutput(projectDetailKey ProjectDetail, projectDetailValue string) string { - return fmt.Sprintf("\t%s%-*s%s", lipgloss.NewStyle().Foreground(views.Green).Render(string(projectDetailKey)), DEFAULT_PADDING-len(string(projectDetailKey)), EMPTY_STRING, projectDetailValue) +func workspaceDetailOutput(workspaceDetailKey WorkspaceDetail, workspaceDetailValue string) string { + return fmt.Sprintf("\t%s%-*s%s", lipgloss.NewStyle().Foreground(views.Green).Render(string(workspaceDetailKey)), DEFAULT_PADDING-len(string(workspaceDetailKey)), EMPTY_STRING, workspaceDetailValue) } -func NewSummaryModel(config SubmissionFormConfig, pcImport *bool) SummaryModel { +func NewSummaryModel(params SubmissionFormParams) SummaryModel { m := SummaryModel{width: maxWidth} m.lg = lipgloss.DefaultRenderer() m.styles = NewStyles(m.lg) - m.name = *config.ChosenName - m.projectList = *config.ProjectList - m.defaults = config.Defaults - m.nameLabel = config.NameLabel + m.workspaceList = *params.WorkspaceList + m.defaults = params.Defaults + m.nameLabel = params.NameLabel - if *config.ChosenName == "" { - *config.ChosenName = config.SuggestedName + if params.ChosenName != nil && *params.ChosenName == "" { + *params.ChosenName = params.SuggestedName } - if !*pcImport { + if params.ImportConfirmation == nil || !*params.ImportConfirmation { m.form = huh.NewForm( huh.NewGroup( huh.NewInput(). - Title(fmt.Sprintf("%s name", config.NameLabel)). - Value(config.ChosenName). + Title(fmt.Sprintf("%s name", params.NameLabel)). + Value(params.ChosenName). Key("name"). Validate(func(str string) error { result, err := util.GetValidatedName(str) if err != nil { return err } - for _, name := range config.ExistingNames { + for _, name := range params.ExistingWorkspaceNames { if name == result { return errors.New("name already exists") } } - *config.ChosenName = result + *params.ChosenName = result return nil }), ), @@ -197,10 +206,17 @@ func NewSummaryModel(config SubmissionFormConfig, pcImport *bool) SummaryModel { huh.NewGroup( huh.NewConfirm(). Title("Is the above information correct?"). - Value(pcImport), + Value(params.ImportConfirmation), ), ).WithShowHelp(false).WithTheme(views.GetCustomTheme()) } + m.form = huh.NewForm( + huh.NewGroup( + huh.NewConfirm(). + Title("Good to go?").Affirmative("Create").Negative("Configure"). + Value(&doneCheck), + ), + ).WithShowHelp(false).WithTheme(views.GetCustomTheme()) return m } @@ -220,7 +236,7 @@ func (m SummaryModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { case "f10": m.quitting = true m.form.State = huh.StateCompleted - configureCheck = true + doneCheck = false return m, tea.Quit } } @@ -250,13 +266,11 @@ func (m SummaryModel) View() string { view := m.form.WithHeight(5).View() + "\n" + configurationHelpLine - if len(m.projectList) > 1 || len(m.projectList) == 1 && ProjectsConfigurationChanged { - summary, err := RenderSummary(m.name, m.projectList, m.defaults, m.nameLabel) - if err != nil { - log.Fatal(err) - } - view = views.GetBorderedMessage(summary) + "\n" + view + summary, err := RenderSummary(m.name, m.workspaceList, m.defaults, m.nameLabel) + if err != nil { + log.Fatal(err) } + view = views.GetBorderedMessage(summary) + "\n" + view return view } diff --git a/pkg/views/workspace/create/view.go b/pkg/views/workspace/create/view.go index 7cb652dc3d..61b10fb834 100644 --- a/pkg/views/workspace/create/view.go +++ b/pkg/views/workspace/create/view.go @@ -62,15 +62,15 @@ type Model struct { width int } -func GetRepositoryFromUrlInput(multiProject bool, projectOrder int, apiClient *apiclient.APIClient, selectedRepos map[string]int) (*apiclient.GitRepository, error) { +func GetRepositoryFromUrlInput(multiWorkspace bool, workspaceOrder int, apiClient *apiclient.APIClient, selectedRepos map[string]int) (*apiclient.GitRepository, error) { m := Model{width: maxWidth} m.lg = lipgloss.DefaultRenderer() m.styles = NewStyles(m.lg) title := "Git repository" - if multiProject { - title = getOrderNumberString(projectOrder) + " project repository" + if multiWorkspace { + title = getOrderNumberString(workspaceOrder) + " workspace repository" } var initialRepoUrl string @@ -82,7 +82,7 @@ func GetRepositoryFromUrlInput(multiProject bool, projectOrder int, apiClient *a initialRepoInput := huh.NewInput(). Title(title). Value(&initialRepoUrl). - Key("initialProjectRepo"). + Key("initialWorkspaceRepo"). Validate(func(str string) error { if str == previousRepoUrl && previousError != nil { return previousError @@ -125,7 +125,7 @@ func GetRepositoryFromUrlInput(multiProject bool, projectOrder int, apiClient *a return repo, nil } -func RunAddMoreProjectsForm() (bool, error) { +func RunAddMoreWorkspacesForm() (bool, error) { m := Model{width: maxWidth} m.lg = lipgloss.DefaultRenderer() m.styles = NewStyles(m.lg) @@ -134,7 +134,7 @@ func RunAddMoreProjectsForm() (bool, error) { confirmInput := huh.NewConfirm(). - Title("Add another project?"). + Title("Add another workspace?"). Value(&addMore) m.form = huh.NewForm( diff --git a/pkg/views/workspace/info/multi.go b/pkg/views/workspace/info/multi.go new file mode 100644 index 0000000000..c66886b50a --- /dev/null +++ b/pkg/views/workspace/info/multi.go @@ -0,0 +1,45 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package info + +import ( + "fmt" + "os" + + "github.com/daytonaio/daytona/pkg/apiclient" + "github.com/daytonaio/daytona/pkg/views" + "golang.org/x/term" +) + +func RenderMulti(workspaces []apiclient.WorkspaceDTO, ide string, forceUnstyled bool) { + var output string + + output += "\n" + + output += getInfoLine("Using Target", workspaces[0].Target.Name) + "\n" + output += getInfoLine("Target ID", workspaces[0].TargetId) + "\n" + + output += getInfoLine("Editor", ide) + "\n" + + terminalWidth, _, err := term.GetSize(int(os.Stdout.Fd())) + if err != nil { + fmt.Println(output) + return + } + if terminalWidth < views.TUITableMinimumWidth || forceUnstyled { + renderUnstyledInfo(output) + return + } + + output += fmt.Sprintf("%s\n\n", views.SeparatorString) + for index, workspace := range workspaces { + output += getInfoLine(fmt.Sprintf("Workspace #%d", index+1), fmt.Sprintf("%s (%s)", workspace.Name, workspace.Id)) + "\n" + output += getWorkspaceDataOutput(&workspace, true) + if index < len(workspaces)-1 { + output += fmt.Sprintf("\n%s\n\n", views.SeparatorString) + } + } + + renderTUIView(output, views.GetContainerBreakpointWidth(terminalWidth), true) +} diff --git a/pkg/views/workspace/info/view.go b/pkg/views/workspace/info/view.go index 7a7e198386..23affb1fde 100644 --- a/pkg/views/workspace/info/view.go +++ b/pkg/views/workspace/info/view.go @@ -11,6 +11,7 @@ import ( "github.com/charmbracelet/lipgloss" "github.com/daytonaio/daytona/pkg/apiclient" "github.com/daytonaio/daytona/pkg/views" + views_util "github.com/daytonaio/daytona/pkg/views/util" "golang.org/x/term" ) @@ -45,12 +46,6 @@ func Render(workspace *apiclient.WorkspaceDTO, ide string, forceUnstyled bool) { output += getInfoLine("Editor", ide) + "\n" } - if len(workspace.Projects) == 1 { - output += getSingleProjectOutput(&workspace.Projects[0], isCreationView) - } else { - output += getProjectsOutputs(workspace.Projects, isCreationView) - } - terminalWidth, _, err := term.GetSize(int(os.Stdout.Fd())) if err != nil { fmt.Println(output) @@ -61,10 +56,28 @@ func Render(workspace *apiclient.WorkspaceDTO, ide string, forceUnstyled bool) { return } + output += getWorkspaceDataOutput(workspace, isCreationView) + if !isCreationView { output = views.GetStyledMainTitle("Workspace Info") + "\n" + output } + if len(workspace.Labels) > 0 { + labels := "" + i := 0 + for k, v := range workspace.Labels { + label := fmt.Sprintf("%s=%s\n", k, v) + if i == 0 { + labels += label + "\n" + } else { + labels += getInfoLine("", fmt.Sprintf("%s=%s\n", k, v)) + } + i++ + } + labels = strings.TrimSuffix(labels, "\n") + output += "\n" + strings.TrimSuffix(getInfoLine("Labels", labels), "\n") + } + renderTUIView(output, views.GetContainerBreakpointWidth(terminalWidth), isCreationView) } @@ -86,52 +99,31 @@ func renderTUIView(output string, width int, isCreationView bool) { fmt.Println(content) } -func getSingleProjectOutput(project *apiclient.Project, isCreationView bool) string { +func getWorkspaceDataOutput(workspace *apiclient.WorkspaceDTO, isCreationView bool) string { var output string var repositoryUrl string - repositoryUrl = project.Repository.Url + repositoryUrl = workspace.Repository.Url repositoryUrl = strings.TrimPrefix(repositoryUrl, "https://") repositoryUrl = strings.TrimPrefix(repositoryUrl, "http://") - if project.State != nil { - output += getInfoLineState("State", project.State) + "\n" - output += getInfoLineGitStatus("Branch", project.State.GitStatus) + "\n" + output += getInfoLineState("State", workspace.State, workspace.Metadata) + "\n" + if workspace.State.Error != nil { + output += getInfoLine("Error", *workspace.State.Error) + "\n" } - output += getInfoLinePrNumber(project.Repository.PrNumber, project.Repository, project.State) - - if !isCreationView { - output += getInfoLine("Target", project.Target) + "\n" + if workspace.Metadata != nil && workspace.Metadata.GitStatus != nil { + output += getInfoLineGitStatus("Branch", workspace.Metadata.GitStatus) + "\n" } - output += getInfoLine("Repository", repositoryUrl) + + output += getInfoLinePrNumber(workspace.Repository.PrNumber, workspace.Repository, workspace.Metadata) if !isCreationView { - output += "\n" - output += getInfoLine("Project", project.Name) + output += getInfoLine("Target", fmt.Sprintf("%s (%s)", workspace.Target.Name, workspace.TargetId)) + "\n" } - return output -} - -func getProjectsOutputs(projects []apiclient.Project, isCreationView bool) string { - var output string - for i, project := range projects { - output += getInfoLine(fmt.Sprintf("Project #%d", i+1), project.Name) - output += getInfoLineState("State", project.State) - if project.State != nil { - output += getInfoLineGitStatus("Branch", project.State.GitStatus) - } - output += getInfoLinePrNumber(project.Repository.PrNumber, project.Repository, project.State) + output += getInfoLine("Repository", repositoryUrl) - if !isCreationView { - output += getInfoLine("Target", project.Target) - } - output += getInfoLine("Repository", project.Repository.Url) - if project.Name != projects[len(projects)-1].Name { - output += "\n" - } - } return output } @@ -139,73 +131,67 @@ func getInfoLine(key, value string) string { return propertyNameStyle.Render(fmt.Sprintf("%-*s", propertyNameWidth, key)) + propertyValueStyle.Render(value) + "\n" } -func getInfoLineState(key string, state *apiclient.ProjectState) string { - var uptime int - var stateProperty string - - if state == nil { - uptime = 0 - } else { - uptime = int(state.Uptime) - } +func getInfoLineState(key string, state apiclient.ResourceState, metadata *apiclient.WorkspaceMetadata) string { + stateLabel := views.GetStateLabel(state.Name) - if uptime == 0 { - stateProperty = propertyValueStyle.Foreground(views.Gray).Render("STOPPED") - } else { - stateProperty = propertyValueStyle.Foreground(views.Green).Render("RUNNING") + if metadata != nil { + views_util.CheckAndAppendTimeLabel(&stateLabel, state, metadata.Uptime) } - return propertyNameStyle.Render(fmt.Sprintf("%-*s", propertyNameWidth, key)) + stateProperty + propertyValueStyle.Foreground(views.Light).Render("\n") + return propertyNameStyle.Render(fmt.Sprintf("%-*s", propertyNameWidth, key)) + stateLabel + propertyValueStyle.Foreground(views.Light).Render("\n") } func getInfoLineGitStatus(key string, status *apiclient.GitStatus) string { + output := propertyNameStyle.Render(fmt.Sprintf("%-*s", propertyNameWidth, key)) + if status == nil { - return "" + return output + propertyValueStyle.Foreground(views.Light).Render("\n") } - output := propertyNameStyle.Render(fmt.Sprintf("%-*s", propertyNameWidth, key)) - output += propertyNameStyle.Foreground(views.Gray).Render(fmt.Sprintf("%-*s", propertyNameWidth, status.CurrentBranch)) + currentBranch := status.CurrentBranch + if status.CurrentBranch == "" { + currentBranch = "/" + } + + output += propertyNameStyle.Foreground(views.Gray).Render(currentBranch) - changesOutput := "" + detailsOutput := "" if status.FileStatus != nil { filesNum := len(status.FileStatus) if filesNum == 1 { - changesOutput = " (1 uncommitted change)" + detailsOutput = " (1 uncommitted change)" } else if filesNum > 1 { - changesOutput = fmt.Sprintf(" (%d uncommitted changes)", filesNum) + detailsOutput = fmt.Sprintf(" (%d uncommitted changes)", filesNum) } } - unpushedOutput := "" - if status.Ahead != nil && *status.Ahead > 0 { if *status.Ahead == 1 { - unpushedOutput += " (1 commit ahead)" + detailsOutput += " (1 commit ahead)" } else { - unpushedOutput += fmt.Sprintf(" (%d commits ahead)", *status.Ahead) + detailsOutput += fmt.Sprintf(" (%d commits ahead)", *status.Ahead) } } if status.Behind != nil && *status.Behind > 0 { if *status.Behind == 1 { - unpushedOutput += " (1 commit behind)" + detailsOutput += " (1 commit behind)" } else { - unpushedOutput += fmt.Sprintf(" (%d commits behind)", *status.Behind) + detailsOutput += fmt.Sprintf(" (%d commits behind)", *status.Behind) } } - branchPublishedOutput := "" if !*status.BranchPublished { - branchPublishedOutput = " (branch not published)" + detailsOutput += " (branch not published)" } - output += changesOutput + unpushedOutput + branchPublishedOutput + propertyValueStyle.Foreground(views.Light).Render("\n") + output += detailsOutput + propertyValueStyle.Foreground(views.Light).Render("\n") return output } -func getInfoLinePrNumber(PrNumber *int32, repo apiclient.GitRepository, state *apiclient.ProjectState) string { - if PrNumber != nil && (state == nil || state.GitStatus.CurrentBranch == repo.Branch) { +func getInfoLinePrNumber(PrNumber *int32, repo apiclient.GitRepository, metadata *apiclient.WorkspaceMetadata) string { + if PrNumber != nil && (metadata == nil || metadata.GitStatus.CurrentBranch == repo.Branch) { return getInfoLine("PR Number", fmt.Sprintf("#%d", *PrNumber)) + "\n" } return "" diff --git a/pkg/views/workspace/list/view.go b/pkg/views/workspace/list/view.go index 52aef25c1e..e12d0c1956 100644 --- a/pkg/views/workspace/list/view.go +++ b/pkg/views/workspace/list/view.go @@ -18,57 +18,31 @@ import ( type RowData struct { Name string Repository string - Target string + TargetName string Status string - Created string Branch string + Uptime string } -func ListWorkspaces(workspaceList []apiclient.WorkspaceDTO, specifyGitProviders bool, verbose bool, activeProfileName string) { +func ListWorkspaces(workspaceList []apiclient.WorkspaceDTO, specifyGitProviders bool, activeProfileName string) { if len(workspaceList) == 0 { views_util.NotifyEmptyWorkspaceList(true) return } - SortWorkspaces(&workspaceList, verbose) + SortWorkspaces(&workspaceList) - headers := []string{"Workspace", "Repository", "Target", "Status", "Created", "Branch"} + headers := []string{"Workspace", "Repository", "Target", "Status", "Branch"} data := [][]string{} - for _, workspace := range workspaceList { + for _, target := range workspaceList { var rowData *RowData var row []string - if len(workspace.Projects) == 1 { - rowData = getWorkspaceTableRowData(workspace, specifyGitProviders) - row = getRowFromRowData(*rowData, false) - data = append(data, row) - } else { - row = getRowFromRowData(RowData{Name: workspace.Name}, true) - data = append(data, row) - for _, project := range workspace.Projects { - rowData = getProjectTableRowData(workspace, project, specifyGitProviders) - if rowData == nil { - continue - } - row = getRowFromRowData(*rowData, false) - data = append(data, row) - } - } - } - - if !verbose { - headers = headers[:len(headers)-2] - for value := range data { - data[value] = data[value][:len(data[value])-2] - } - } else { - // Temporarily hiding the branch column - headers = headers[:len(headers)-1] - for value := range data { - data[value] = data[value][:len(data[value])-1] - } + rowData = getTableRowData(target, specifyGitProviders) + row = getRowFromRowData(*rowData, false) + data = append(data, row) } footer := lipgloss.NewStyle().Foreground(views.LightGray).Render(views.GetListFooter(activeProfileName, &views.Padding{})) @@ -80,114 +54,57 @@ func ListWorkspaces(workspaceList []apiclient.WorkspaceDTO, specifyGitProviders fmt.Println(table) } -func renderUnstyledList(workspaceList []apiclient.WorkspaceDTO) { - for _, workspace := range workspaceList { - info_view.Render(&workspace, "", true) - - if workspace.Id != workspaceList[len(workspaceList)-1].Id { - fmt.Printf("\n%s\n\n", views.SeparatorString) - } - - } -} - -func getRowFromRowData(rowData RowData, isMultiProjectAccordion bool) []string { - var state string - if rowData.Status == "" { - state = views.InactiveStyle.Render("STOPPED") - } else { - state = views.ActiveStyle.Render("RUNNING") - } - - if isMultiProjectAccordion { - return []string{rowData.Name, "", "", "", "", ""} - } - - row := []string{ - views.NameStyle.Render(rowData.Name), - views.DefaultRowDataStyle.Render(rowData.Repository), - views.DefaultRowDataStyle.Render(rowData.Target), - state, - views.DefaultRowDataStyle.Render(rowData.Created), - views.DefaultRowDataStyle.Render(views.GetBranchNameLabel(rowData.Branch)), - } - - if rowData.Status != "" { - row[3] = fmt.Sprintf("%s %s", state, views.DefaultRowDataStyle.Render(fmt.Sprintf("(%s)", rowData.Status))) - } - - return row -} - -func SortWorkspaces(workspaceList *[]apiclient.WorkspaceDTO, verbose bool) { - if verbose { - sort.Slice(*workspaceList, func(i, j int) bool { - ws1 := (*workspaceList)[i] - ws2 := (*workspaceList)[j] - if ws1.Info == nil || ws2.Info == nil || ws1.Info.Projects == nil || ws2.Info.Projects == nil { - return true - } - if len(ws1.Info.Projects) == 0 || len(ws2.Info.Projects) == 0 { - return true - } - return ws1.Info.Projects[0].Created > ws2.Info.Projects[0].Created - }) - return - } - +func SortWorkspaces(workspaceList *[]apiclient.WorkspaceDTO) { sort.Slice(*workspaceList, func(i, j int) bool { - ws1 := (*workspaceList)[i] - ws2 := (*workspaceList)[j] - if len(ws1.Projects) == 0 || len(ws2.Projects) == 0 || ws1.Projects[0].State == nil || ws2.Projects[0].State == nil { - return true + pi, pj := views_util.GetStateSortPriorities((*workspaceList)[i].State.Name, (*workspaceList)[j].State.Name) + if pi != pj { + return pi < pj } - return ws1.Projects[0].State.Uptime < ws2.Projects[0].State.Uptime - }) + // If two workspaces have the same state priority, compare the UpdatedAt property + return (*workspaceList)[i].State.UpdatedAt > (*workspaceList)[j].State.UpdatedAt + }) } -func getWorkspaceTableRowData(workspace apiclient.WorkspaceDTO, specifyGitProviders bool) *RowData { +func getTableRowData(workspace apiclient.WorkspaceDTO, specifyGitProviders bool) *RowData { rowData := RowData{"", "", "", "", "", ""} rowData.Name = workspace.Name + views_util.AdditionalPropertyPadding - if len(workspace.Projects) > 0 { - rowData.Repository = util.GetRepositorySlugFromUrl(workspace.Projects[0].Repository.Url, specifyGitProviders) - rowData.Branch = workspace.Projects[0].Repository.Branch - } + rowData.Repository = util.GetRepositorySlugFromUrl(workspace.Repository.Url, specifyGitProviders) + rowData.Branch = workspace.Repository.Branch + rowData.Status = views.GetStateLabel(workspace.State.Name) - rowData.Target = workspace.Target + views_util.AdditionalPropertyPadding + rowData.TargetName = workspace.Target.Name + views_util.AdditionalPropertyPadding - if workspace.Info != nil && workspace.Info.Projects != nil && len(workspace.Info.Projects) > 0 { - rowData.Created = util.FormatTimestamp(workspace.Info.Projects[0].Created) - } - if len(workspace.Projects) > 0 && workspace.Projects[0].State != nil && workspace.Projects[0].State.Uptime > 0 { - rowData.Status = util.FormatUptime(workspace.Projects[0].State.Uptime) + if workspace.Metadata != nil { + views_util.CheckAndAppendTimeLabel(&rowData.Status, workspace.State, workspace.Metadata.Uptime) } + return &rowData } -func getProjectTableRowData(workspaceDTO apiclient.WorkspaceDTO, project apiclient.Project, specifyGitProviders bool) *RowData { - rowData := RowData{"", "", "", "", "", ""} - rowData.Name = " └ " + project.Name - - rowData.Repository = util.GetRepositorySlugFromUrl(project.Repository.Url, specifyGitProviders) - rowData.Branch = project.Repository.Branch +func renderUnstyledList(workspaceList []apiclient.WorkspaceDTO) { + for _, workspace := range workspaceList { + info_view.Render(&workspace, "", true) - rowData.Target = project.Target + views_util.AdditionalPropertyPadding + if workspace.Id != workspaceList[len(workspaceList)-1].Id { + fmt.Printf("\n%s\n\n", views.SeparatorString) + } - if project.State != nil && project.State.Uptime > 0 { - rowData.Status = util.FormatUptime(project.State.Uptime) } +} - if workspaceDTO.Info == nil || workspaceDTO.Info.Projects == nil { - return &rowData +func getRowFromRowData(rowData RowData, isMultiWorkspaceAccordion bool) []string { + if isMultiWorkspaceAccordion { + return []string{rowData.Name, "", "", "", "", ""} } - for _, projectInfo := range workspaceDTO.Info.Projects { - if projectInfo.Name == project.Name { - rowData.Created = util.FormatTimestamp(projectInfo.Created) - break - } + row := []string{ + views.NameStyle.Render(rowData.Name), + views.DefaultRowDataStyle.Render(rowData.Repository), + views.DefaultRowDataStyle.Render(rowData.TargetName), + rowData.Status, + views.DefaultRowDataStyle.Render(views.GetBranchNameLabel(rowData.Branch)), } - return &rowData + return row } diff --git a/pkg/views/workspace/selection/project.go b/pkg/views/workspace/selection/project.go deleted file mode 100644 index 373a0546bc..0000000000 --- a/pkg/views/workspace/selection/project.go +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package selection - -import ( - "fmt" - "os" - - "github.com/daytonaio/daytona/pkg/apiclient" - "github.com/daytonaio/daytona/pkg/views" - - "github.com/charmbracelet/bubbles/list" - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" -) - -func GetProjectFromPrompt(projects []apiclient.Project, actionVerb string) *apiclient.Project { - choiceChan := make(chan *apiclient.Project) - go selectProjectPrompt(projects, actionVerb, choiceChan) - return <-choiceChan -} - -func selectProjectPrompt(projects []apiclient.Project, actionVerb string, choiceChan chan<- *apiclient.Project) { - items := []list.Item{} - - for _, project := range projects { - projectName := project.Name - if project.Name == "" { - projectName = "Unnamed Project" - } - - newItem := item[apiclient.Project]{title: projectName, desc: "", choiceProperty: project} - items = append(items, newItem) - } - - d := list.NewDefaultDelegate() - - d.Styles.SelectedTitle = lipgloss.NewStyle(). - Border(lipgloss.NormalBorder(), false, false, false, true). - BorderForeground(views.Green). - Foreground(views.Green). - Bold(true). - Padding(0, 0, 0, 1) - - d.Styles.SelectedDesc = d.Styles.SelectedTitle.Foreground(views.DimmedGreen) - - l := list.New(items, d, 0, 0) - - l.Styles.FilterPrompt = lipgloss.NewStyle().Foreground(views.Green) - l.Styles.FilterCursor = lipgloss.NewStyle().Foreground(views.Green) - - l.FilterInput.PromptStyle = lipgloss.NewStyle().Foreground(views.Green) - l.FilterInput.TextStyle = lipgloss.NewStyle().Foreground(views.Green) - - m := model[apiclient.Project]{list: l} - - m.list.Title = views.GetStyledMainTitle("Select a Project To " + actionVerb) - m.list.Styles.Title = lipgloss.NewStyle().Foreground(views.Green).Bold(true) - - p, err := tea.NewProgram(m, tea.WithAltScreen()).Run() - if err != nil { - fmt.Println("Error running program:", err) - os.Exit(1) - } - - if m, ok := p.(model[apiclient.Project]); ok && m.choice != nil { - choiceChan <- m.choice - } else { - choiceChan <- nil - } -} diff --git a/pkg/views/workspace/selection/projectconfig.go b/pkg/views/workspace/selection/projectconfig.go deleted file mode 100644 index b9783b6043..0000000000 --- a/pkg/views/workspace/selection/projectconfig.go +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package selection - -import ( - "fmt" - "os" - - "github.com/daytonaio/daytona/pkg/apiclient" - "github.com/daytonaio/daytona/pkg/views" - - "github.com/charmbracelet/bubbles/list" - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" -) - -var BlankProjectIdentifier = "" -var NewProjectConfigIdentifier = "" - -func GetProjectConfigFromPrompt(projectConfigs []apiclient.ProjectConfig, projectOrder int, showBlankOption, withNewProjectConfig bool, actionVerb string) *apiclient.ProjectConfig { - choiceChan := make(chan *apiclient.ProjectConfig) - go selectProjectConfigPrompt(projectConfigs, projectOrder, showBlankOption, withNewProjectConfig, actionVerb, choiceChan) - return <-choiceChan -} - -func selectProjectConfigPrompt(projectConfigs []apiclient.ProjectConfig, projectOrder int, showBlankOption, withNewProjectConfig bool, actionVerb string, choiceChan chan<- *apiclient.ProjectConfig) { - items := []list.Item{} - - if showBlankOption { - newItem := item[apiclient.ProjectConfig]{title: "Make a blank project", desc: "(default project configuration)", choiceProperty: apiclient.ProjectConfig{ - Name: BlankProjectIdentifier, - }} - items = append(items, newItem) - } - - for _, pc := range projectConfigs { - projectConfigName := pc.Name - if pc.Name == "" { - projectConfigName = "Unnamed Project Config" - } - - newItem := item[apiclient.ProjectConfig]{title: projectConfigName, desc: pc.RepositoryUrl, choiceProperty: pc} - items = append(items, newItem) - } - - if withNewProjectConfig { - newItem := item[apiclient.ProjectConfig]{title: "+ Create a new project configuration", desc: "", choiceProperty: apiclient.ProjectConfig{ - Name: NewProjectConfigIdentifier, - }} - items = append(items, newItem) - } - - d := list.NewDefaultDelegate() - - d.Styles.SelectedTitle = lipgloss.NewStyle(). - Border(lipgloss.NormalBorder(), false, false, false, true). - BorderForeground(views.Green). - Foreground(views.Green). - Bold(true). - Padding(0, 0, 0, 1) - - d.Styles.SelectedDesc = d.Styles.SelectedTitle.Foreground(views.DimmedGreen) - - l := list.New(items, d, 0, 0) - - l.Styles.FilterPrompt = lipgloss.NewStyle().Foreground(views.Green) - l.Styles.FilterCursor = lipgloss.NewStyle().Foreground(views.Green) - - l.FilterInput.PromptStyle = lipgloss.NewStyle().Foreground(views.Green) - l.FilterInput.TextStyle = lipgloss.NewStyle().Foreground(views.Green) - - title := "Select a Project Config To " + actionVerb - if projectOrder > 1 { - title += fmt.Sprintf(" (Project #%d)", projectOrder) - } - l.Title = views.GetStyledMainTitle(title) - l.Styles.Title = titleStyle - - m := model[apiclient.ProjectConfig]{list: l} - - p, err := tea.NewProgram(m, tea.WithAltScreen()).Run() - if err != nil { - fmt.Println("Error running program:", err) - os.Exit(1) - } - - if m, ok := p.(model[apiclient.ProjectConfig]); ok && m.choice != nil { - choiceChan <- m.choice - } else { - choiceChan <- nil - } -} diff --git a/pkg/views/workspace/selection/view.go b/pkg/views/workspace/selection/view.go index 5e08d8d69c..21bc7d517c 100644 --- a/pkg/views/workspace/selection/view.go +++ b/pkg/views/workspace/selection/view.go @@ -15,14 +15,11 @@ import ( tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" "github.com/daytonaio/daytona/cmd/daytona/config" + "github.com/daytonaio/daytona/pkg/apiclient" "github.com/daytonaio/daytona/pkg/views" "golang.org/x/term" ) -var CustomRepoIdentifier = "" - -const CREATE_FROM_SAMPLE = "" - var selectedStyles = lipgloss.NewStyle(). Border(lipgloss.NormalBorder(), false, false, false, true). BorderForeground(views.Green). @@ -38,20 +35,23 @@ var statusMessageDangerStyle = lipgloss.NewStyle().Bold(true). Render type item[T any] struct { - id, title, desc, createdTime, uptime, target string - choiceProperty T - isMarked bool - isMultipleSelect bool - action string + id, title, desc, targetName, repository, createdTime, state string + workspace *apiclient.WorkspaceDTO + choiceProperty T + isMarked bool + isMultipleSelect bool + isDisabled bool + action string } func (i item[T]) Title() string { return i.title } func (i item[T]) Id() string { return i.id } func (i item[T]) Description() string { return i.desc } -func (i item[T]) FilterValue() string { return i.title } +func (i item[T]) TargetName() string { return i.targetName } +func (i item[T]) Repository() string { return i.repository } func (i item[T]) CreatedTime() string { return i.createdTime } -func (i item[T]) Uptime() string { return i.uptime } -func (i item[T]) Target() string { return i.target } +func (i item[T]) State() string { return i.state } +func (i item[T]) FilterValue() string { return i.title } type model[T any] struct { list list.Model @@ -76,12 +76,59 @@ func (m model[T]) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg := msg.(type) { case tea.KeyMsg: switch keypress := msg.String(); keypress { + case "down", "j": + for { + isSubsequentItemsDisabled := true + curIndex := m.list.Index() + lastIndex := len(m.list.Items()) - 1 + for i := curIndex + 1; i <= lastIndex; i++ { + if !m.list.Items()[i].(item[T]).isDisabled { + isSubsequentItemsDisabled = false + break + } + } + // no need of moving cursor down if all subsequent items after current index have + // disabled property true. + if isSubsequentItemsDisabled { + break + } + m.list.CursorDown() + item := m.list.SelectedItem().(item[T]) + if !item.isDisabled { + break + } + } + return m, nil + + case "up", "k": + for { + isPrecedingItemsDisabled := true + curIndex := m.list.Index() + for i := curIndex - 1; i >= 0; i-- { + if !m.list.Items()[i].(item[T]).isDisabled { + isPrecedingItemsDisabled = false + break + } + } + // no need of moving cursor up if all preceding items before current index have + // disabled property true. + if isPrecedingItemsDisabled { + break + } + m.list.CursorUp() + item := m.list.SelectedItem().(item[T]) + if !item.isDisabled { + break + } + } + return m, nil + case "ctrl+c": return m, tea.Quit case "enter": i, ok := m.list.SelectedItem().(item[T]) - if ok { + if ok && !i.isDisabled { m.choice = &i.choiceProperty } workspaceList := m.list.Items() @@ -89,7 +136,7 @@ func (m model[T]) Update(msg tea.Msg) (tea.Model, tea.Cmd) { for _, workspace := range workspaceList { if workspace.(item[T]).isMarked { workspaceItem, ok := workspace.(item[T]) - if !ok { + if !ok || workspaceItem.isDisabled { continue } choices = append(choices, &workspaceItem.choiceProperty) @@ -149,8 +196,12 @@ func (d ItemDelegate[T]) Render(w io.Writer, m list.Model, index int, listItem l baseStyles := lipgloss.NewStyle().Padding(0, 0, 0, 2) title := baseStyles.Render(i.Title()) - idWithTargetString := fmt.Sprintf("%s (%s)", i.Id(), i.Target()) + idWithTargetString := fmt.Sprintf("%s (%s)", i.Id(), i.TargetName()) + if i.Id() == NewWorkspaceIdentifier { + idWithTargetString = "" + } idWithTarget := baseStyles.Foreground(views.Gray).Render(idWithTargetString) + repository := baseStyles.Foreground(views.DimmedGreen).Render(i.Repository()) description := baseStyles.Render(i.Description()) // Add the created/updated time if it's available @@ -158,28 +209,47 @@ func (d ItemDelegate[T]) Render(w io.Writer, m list.Model, index int, listItem l timeStyles := lipgloss.NewStyle(). Align(lipgloss.Right). Width(timeWidth) - timeString := timeStyles.Render("") - if i.Uptime() != "" { - timeString = timeStyles.Render(i.Uptime()) - } else if i.CreatedTime() != "" { - timeString = timeStyles.Render(fmt.Sprintf("created %s", i.CreatedTime())) + stateLabel := timeStyles.Render("") + if i.State() != "" { + stateLabel = timeStyles.Render(i.State()) + } + + if i.isDisabled { + title = baseStyles.Foreground(views.Gray).Render(i.Title()) + idWithTarget = baseStyles.Foreground(views.Gray).Render(idWithTargetString) + repository = baseStyles.Foreground(views.Gray).Render(i.Repository()) + description = baseStyles.Foreground(views.Gray).Render(i.Description()) + stateLabel = timeStyles.Foreground(views.Gray).Render(stateLabel) } // Adjust styles as the user moves through the menu if isSelected { - title = selectedStyles.Foreground(views.Green).Render(i.Title()) - idWithTarget = selectedStyles.Foreground(views.Gray).Render(idWithTargetString) - description = selectedStyles.Foreground(views.DimmedGreen).Render(i.Description()) - timeString = timeStyles.Foreground(views.DimmedGreen).Render(timeString) + if !i.isDisabled { + title = selectedStyles.Foreground(views.Green).Render(i.Title()) + idWithTarget = selectedStyles.Foreground(views.Gray).Render(idWithTargetString) + repository = selectedStyles.Foreground(views.DimmedGreen).Render(i.Repository()) + description = selectedStyles.Foreground(views.DimmedGreen).Render(i.Description()) + stateLabel = timeStyles.Foreground(views.DimmedGreen).Render(stateLabel) + } else { + title = selectedStyles.Render(i.Title()) + idWithTarget = selectedStyles.Foreground(views.Gray).Render(idWithTargetString) + repository = selectedStyles.Foreground(views.LightGray).Render(i.Repository()) + description = selectedStyles.Foreground(views.LightGray).Render(i.Description()) + stateLabel = timeStyles.Foreground(views.LightGray).Render(stateLabel) + } } // Render to the terminal - s.WriteString(lipgloss.JoinHorizontal(lipgloss.Bottom, title, timeString)) + s.WriteString(lipgloss.JoinHorizontal(lipgloss.Bottom, title, stateLabel)) s.WriteRune('\n') s.WriteString(idWithTarget) s.WriteRune('\n') - s.WriteString(description) + s.WriteString(repository) s.WriteRune('\n') + if i.Description() != "" { + s.WriteString(description) + s.WriteRune('\n') + } fmt.Fprint(w, s.String()) } @@ -209,6 +279,9 @@ func (d ItemDelegate[T]) Update(msg tea.Msg, m *list.Model) tea.Cmd { if !i.isMultipleSelect { return nil } + if i.isDisabled { + return m.NewStatusMessage(statusMessageGreenStyle("Workspace ") + i.title + statusMessageGreenStyle(" selection is disabled for this action")) + } if i.isMarked { i.title = strings.TrimPrefix(i.title, statusMessageDangerStyle(fmt.Sprintf("%s: ", i.action))) i.isMarked = false diff --git a/pkg/views/workspace/selection/workspace.go b/pkg/views/workspace/selection/workspace.go index 231820a579..998b496501 100644 --- a/pkg/views/workspace/selection/workspace.go +++ b/pkg/views/workspace/selection/workspace.go @@ -6,74 +6,87 @@ package selection import ( "fmt" "os" - "strings" "github.com/charmbracelet/bubbles/list" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" - "github.com/daytonaio/daytona/internal/util" "github.com/daytonaio/daytona/pkg/apiclient" "github.com/daytonaio/daytona/pkg/views" + views_util "github.com/daytonaio/daytona/pkg/views/util" list_view "github.com/daytonaio/daytona/pkg/views/workspace/list" ) -func generateWorkspaceList(workspaces []apiclient.WorkspaceDTO, isMultipleSelect bool, action string) []list.Item { +var NewWorkspaceIdentifier = "" +type ActionVerb string + +var StartActionVerb ActionVerb = "Start" +var StopActionVerb ActionVerb = "Stop" +var RestartActionVerb ActionVerb = "Restart" +var DeleteActionVerb ActionVerb = "Delete" + +func generateWorkspaceList(workspaces []apiclient.WorkspaceDTO, isMultipleSelect bool, action ActionVerb) []list.Item { // Initialize an empty list of items. items := []list.Item{} + enabledItems := []list.Item{} + disabledItems := []list.Item{} // Populate items with titles and descriptions from workspaces. for _, workspace := range workspaces { - var projectsInfo []string - - if len(workspace.Projects) == 0 { - continue + workspaceName := workspace.Name + if workspace.Name == "" { + workspaceName = "Unnamed Workspace" } - if len(workspace.Projects) == 1 { - projectsInfo = append(projectsInfo, util.GetRepositorySlugFromUrl(workspace.Projects[0].Repository.Url, true)) - } else { - for _, project := range workspace.Projects { - projectsInfo = append(projectsInfo, project.Name) + stateLabel := views.GetStateLabel(workspace.State.Name) + + isDisabled := false + switch action { + case StartActionVerb: + if workspace.State.Name == apiclient.ResourceStateNameStarted { + isDisabled = true + } + case StopActionVerb, RestartActionVerb: + if workspace.State.Name == apiclient.ResourceStateNameStopped { + isDisabled = true } } - // Get the time if available - uptime := "" - createdTime := "" - if workspace.Info != nil && workspace.Info.Projects != nil && len(workspace.Info.Projects) > 0 { - createdTime = util.FormatTimestamp(workspace.Info.Projects[0].Created) - } - if len(workspace.Projects) > 0 && workspace.Projects[0].State != nil { - if workspace.Projects[0].State.Uptime == 0 { - uptime = "STOPPED" - } else { - uptime = fmt.Sprintf("up %s", util.FormatUptime(workspace.Projects[0].State.Uptime)) - } + if workspace.Metadata != nil { + views_util.CheckAndAppendTimeLabel(&stateLabel, workspace.State, workspace.Metadata.Uptime) } newItem := item[apiclient.WorkspaceDTO]{ - title: workspace.Name, + title: workspaceName, id: workspace.Id, - desc: strings.Join(projectsInfo, ", "), - createdTime: createdTime, - uptime: uptime, - target: workspace.Target, + desc: "", + targetName: workspace.Target.Name, + repository: workspace.Repository.Url, + state: stateLabel, + workspace: &workspace, choiceProperty: workspace, + isDisabled: isDisabled, } if isMultipleSelect { newItem.isMultipleSelect = true - newItem.action = action + newItem.action = string(action) } - items = append(items, newItem) + if isDisabled { + disabledItems = append(disabledItems, newItem) + } else { + enabledItems = append(enabledItems, newItem) + } } + items = append(items, enabledItems...) + items = append(items, disabledItems...) + return items } -func getWorkspaceProgramEssentials(modelTitle string, actionVerb string, workspaces []apiclient.WorkspaceDTO, footerText string, isMultipleSelect bool) tea.Model { +func getWorkspaceProgramEssentials(modelTitle string, actionVerb ActionVerb, workspaces []apiclient.WorkspaceDTO, footerText string, isMultipleSelect bool) tea.Model { items := generateWorkspaceList(workspaces, isMultipleSelect, actionVerb) @@ -89,7 +102,7 @@ func getWorkspaceProgramEssentials(modelTitle string, actionVerb string, workspa m := model[apiclient.WorkspaceDTO]{list: l} - m.list.Title = views.GetStyledMainTitle(modelTitle + actionVerb) + m.list.Title = views.GetStyledMainTitle(modelTitle + string(actionVerb)) m.list.Styles.Title = lipgloss.NewStyle().Foreground(views.Green).Bold(true) m.footer = footerText @@ -103,8 +116,8 @@ func getWorkspaceProgramEssentials(modelTitle string, actionVerb string, workspa return p } -func selectWorkspacePrompt(workspaces []apiclient.WorkspaceDTO, actionVerb string, choiceChan chan<- *apiclient.WorkspaceDTO) { - list_view.SortWorkspaces(&workspaces, true) +func selectWorkspacePrompt(workspaces []apiclient.WorkspaceDTO, actionVerb ActionVerb, choiceChan chan<- *apiclient.WorkspaceDTO) { + list_view.SortWorkspaces(&workspaces) p := getWorkspaceProgramEssentials("Select a Workspace To ", actionVerb, workspaces, "", false) if m, ok := p.(model[apiclient.WorkspaceDTO]); ok && m.choice != nil { @@ -114,7 +127,7 @@ func selectWorkspacePrompt(workspaces []apiclient.WorkspaceDTO, actionVerb strin } } -func GetWorkspaceFromPrompt(workspaces []apiclient.WorkspaceDTO, actionVerb string) *apiclient.WorkspaceDTO { +func GetWorkspaceFromPrompt(workspaces []apiclient.WorkspaceDTO, actionVerb ActionVerb) *apiclient.WorkspaceDTO { choiceChan := make(chan *apiclient.WorkspaceDTO) go selectWorkspacePrompt(workspaces, actionVerb, choiceChan) @@ -122,10 +135,10 @@ func GetWorkspaceFromPrompt(workspaces []apiclient.WorkspaceDTO, actionVerb stri return <-choiceChan } -func selectWorkspacesFromPrompt(workspaces []apiclient.WorkspaceDTO, actionVerb string, choiceChan chan<- []*apiclient.WorkspaceDTO) { - list_view.SortWorkspaces(&workspaces, true) +func selectWorkspacesFromPrompt(workspaces []apiclient.WorkspaceDTO, actionVerb ActionVerb, choiceChan chan<- []*apiclient.WorkspaceDTO) { + list_view.SortWorkspaces(&workspaces) - footerText := lipgloss.NewStyle().Bold(true).PaddingLeft(2).Render(fmt.Sprintf("\n\nPress 'x' to mark workspace.\nPress 'enter' to %s the current/marked workspaces.", actionVerb)) + footerText := lipgloss.NewStyle().Bold(true).PaddingLeft(2).Render(fmt.Sprintf("\n\nPress 'x' to mark a workspace.\nPress 'enter' to %s the current/marked workspaces.", actionVerb)) p := getWorkspaceProgramEssentials("Select Workspaces To ", actionVerb, workspaces, footerText, true) m, ok := p.(model[apiclient.WorkspaceDTO]) @@ -138,7 +151,7 @@ func selectWorkspacesFromPrompt(workspaces []apiclient.WorkspaceDTO, actionVerb } } -func GetWorkspacesFromPrompt(workspaces []apiclient.WorkspaceDTO, actionVerb string) []*apiclient.WorkspaceDTO { +func GetWorkspacesFromPrompt(workspaces []apiclient.WorkspaceDTO, actionVerb ActionVerb) []*apiclient.WorkspaceDTO { choiceChan := make(chan []*apiclient.WorkspaceDTO) go selectWorkspacesFromPrompt(workspaces, actionVerb, choiceChan) diff --git a/pkg/views/projectconfig/info/view.go b/pkg/views/workspacetemplate/info/view.go similarity index 62% rename from pkg/views/projectconfig/info/view.go rename to pkg/views/workspacetemplate/info/view.go index 84ffd20f37..4e0774fd76 100644 --- a/pkg/views/projectconfig/info/view.go +++ b/pkg/views/workspacetemplate/info/view.go @@ -27,61 +27,61 @@ var propertyValueStyle = lipgloss.NewStyle(). var prebuildDetailStyle = propertyNameStyle -func Render(projectConfig *apiclient.ProjectConfig, apiServerConfig *apiclient.ServerConfig, forceUnstyled bool) { +func Render(workspaceTemplate *apiclient.WorkspaceTemplate, apiServerConfig *apiclient.ServerConfig, forceUnstyled bool) { var output string output += "\n\n" - output += views.GetStyledMainTitle("Project Config Info") + "\n\n" + output += views.GetStyledMainTitle("Workspace Template Info") + "\n\n" - output += getInfoLine("Name", projectConfig.Name) + "\n" + output += getInfoLine("Name", workspaceTemplate.Name) + "\n" - output += getInfoLine("Repository", projectConfig.RepositoryUrl) + "\n" + output += getInfoLine("Repository", workspaceTemplate.RepositoryUrl) + "\n" gitProviderConfig := "/" - if projectConfig.GitProviderConfigId != nil { - gitProviderConfig = *projectConfig.GitProviderConfigId + if workspaceTemplate.GitProviderConfigId != nil { + gitProviderConfig = *workspaceTemplate.GitProviderConfigId } output += getInfoLine("Git Provider ID", gitProviderConfig) + "\n" - if projectConfig.Default { + if workspaceTemplate.Default { output += getInfoLine("Default", "Yes") + "\n" } - if GetLabelFromBuild(projectConfig.BuildConfig) != "" { - projectDefaults := &views_util.ProjectConfigDefaults{ - Image: &apiServerConfig.DefaultProjectImage, - ImageUser: &apiServerConfig.DefaultProjectUser, + if GetLabelFromBuild(workspaceTemplate.BuildConfig) != "" { + workspaceDefaults := &views_util.WorkspaceTemplateDefaults{ + Image: &apiServerConfig.DefaultWorkspaceImage, + ImageUser: &apiServerConfig.DefaultWorkspaceUser, } - createProjectDto := apiclient.CreateProjectDTO{ - BuildConfig: projectConfig.BuildConfig, + createWorkspaceDto := apiclient.CreateWorkspaceDTO{ + BuildConfig: workspaceTemplate.BuildConfig, } - _, buildChoice := views_util.GetProjectBuildChoice(createProjectDto, projectDefaults) + _, buildChoice := views_util.GetWorkspaceBuildChoice(createWorkspaceDto, workspaceDefaults) output += getInfoLine("Build", buildChoice) + "\n" } - if projectConfig.Image != "" { - output += getInfoLine("Image", projectConfig.Image) + "\n" + if workspaceTemplate.Image != "" { + output += getInfoLine("Image", workspaceTemplate.Image) + "\n" } - if projectConfig.User != "" { - output += getInfoLine("User", projectConfig.User) + "\n" + if workspaceTemplate.User != "" { + output += getInfoLine("User", workspaceTemplate.User) + "\n" } - if projectConfig.BuildConfig != nil && projectConfig.BuildConfig.Devcontainer != nil { - output += getInfoLine("Devcontainer path", projectConfig.BuildConfig.Devcontainer.FilePath) + "\n" + if workspaceTemplate.BuildConfig != nil && workspaceTemplate.BuildConfig.Devcontainer != nil { + output += getInfoLine("Devcontainer path", workspaceTemplate.BuildConfig.Devcontainer.FilePath) + "\n" } - prebuildCount := len(projectConfig.Prebuilds) + prebuildCount := len(workspaceTemplate.Prebuilds) if prebuildCount > 0 { if prebuildCount == 1 { - output += getInfoLine("Prebuild: ", getPrebuildLine(projectConfig.Prebuilds[0], nil)) + "\n" + output += getInfoLine("Prebuild: ", getPrebuildLine(workspaceTemplate.Prebuilds[0], nil)) + "\n" } else { output += getInfoLine("Prebuilds: ", "") + "\n" - for i, prebuild := range projectConfig.Prebuilds { - if len(projectConfig.Prebuilds) != 1 { + for i, prebuild := range workspaceTemplate.Prebuilds { + if len(workspaceTemplate.Prebuilds) != 1 { output += getPrebuildLine(prebuild, util.Pointer(i+1)) + "\n" } else { output += getPrebuildLine(prebuild, nil) + "\n" diff --git a/pkg/views/workspacetemplate/list/view.go b/pkg/views/workspacetemplate/list/view.go new file mode 100644 index 0000000000..80e135c6c9 --- /dev/null +++ b/pkg/views/workspacetemplate/list/view.go @@ -0,0 +1,91 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package list + +import ( + "fmt" + + "github.com/daytonaio/daytona/internal/util" + "github.com/daytonaio/daytona/pkg/apiclient" + "github.com/daytonaio/daytona/pkg/views" + views_util "github.com/daytonaio/daytona/pkg/views/util" + "github.com/daytonaio/daytona/pkg/views/workspacetemplate/info" +) + +type rowData struct { + Name string + Repository string + Build string + Prebuilds string + IsDefault string +} + +func ListWorkspaceTemplates(workspaceTemplateList []apiclient.WorkspaceTemplate, apiServerConfig *apiclient.ServerConfig, specifyGitProviders bool) { + if len(workspaceTemplateList) == 0 { + views_util.NotifyEmptyWorkspaceTemplateList(true) + return + } + + data := [][]string{} + + for _, wt := range workspaceTemplateList { + data = append(data, getRowFromData(wt, apiServerConfig, specifyGitProviders)) + } + + table := views_util.GetTableView(data, []string{ + "Name", "Repository", "Build", "Prebuild rules", "Default", + }, nil, func() { + renderUnstyledList(workspaceTemplateList, apiServerConfig) + }) + + fmt.Println(table) +} + +func renderUnstyledList(workspaceTemplateList []apiclient.WorkspaceTemplate, apiServerConfig *apiclient.ServerConfig) { + for _, wt := range workspaceTemplateList { + info.Render(&wt, apiServerConfig, true) + + if wt.Name != workspaceTemplateList[len(workspaceTemplateList)-1].Name { + fmt.Printf("\n%s\n\n", views.SeparatorString) + } + } +} + +func getRowFromData(workspaceTemplate apiclient.WorkspaceTemplate, apiServerConfig *apiclient.ServerConfig, specifyGitProviders bool) []string { + var isDefault string + var data rowData + + data.Name = workspaceTemplate.Name + views_util.AdditionalPropertyPadding + data.Repository = util.GetRepositorySlugFromUrl(workspaceTemplate.RepositoryUrl, specifyGitProviders) + data.Prebuilds = "None" + + workspaceDefaults := &views_util.WorkspaceTemplateDefaults{ + Image: &apiServerConfig.DefaultWorkspaceImage, + ImageUser: &apiServerConfig.DefaultWorkspaceUser, + } + + createWorkspaceDto := apiclient.CreateWorkspaceDTO{ + BuildConfig: workspaceTemplate.BuildConfig, + } + + _, data.Build = views_util.GetWorkspaceBuildChoice(createWorkspaceDto, workspaceDefaults) + + if workspaceTemplate.Default { + isDefault = views.ActiveStyle.Render("Yes") + } else { + isDefault = views.InactiveStyle.Render("/") + } + + if len(workspaceTemplate.Prebuilds) > 0 { + data.Prebuilds = fmt.Sprintf("%d", len(workspaceTemplate.Prebuilds)) + } + + return []string{ + views.NameStyle.Render(data.Name), + views.DefaultRowDataStyle.Render(data.Repository), + views.DefaultRowDataStyle.Render(data.Build), + views.DefaultRowDataStyle.Render(data.Prebuilds), + isDefault, + } +} diff --git a/pkg/workspace/project/buildconfig/config.go b/pkg/workspace/project/buildconfig/config.go deleted file mode 100644 index 30273d3017..0000000000 --- a/pkg/workspace/project/buildconfig/config.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package buildconfig - -type BuildConfig struct { - Devcontainer *DevcontainerConfig `json:"devcontainer,omitempty" validate:"optional"` - CachedBuild *CachedBuild `json:"cachedBuild,omitempty" validate:"optional"` -} // @name BuildConfig - -type DevcontainerConfig struct { - FilePath string `json:"filePath" validate:"required"` -} // @name DevcontainerConfig - -type CachedBuild struct { - User string `json:"user" validate:"required"` - Image string `json:"image" validate:"required"` -} // @name CachedBuild diff --git a/pkg/workspace/project/config/config.go b/pkg/workspace/project/config/config.go deleted file mode 100644 index 86f6d9ed97..0000000000 --- a/pkg/workspace/project/config/config.go +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package config - -import ( - "errors" - - "github.com/daytonaio/daytona/pkg/workspace/project/buildconfig" -) - -type ProjectConfig struct { - Name string `json:"name" validate:"required"` - Image string `json:"image" validate:"required"` - User string `json:"user" validate:"required"` - BuildConfig *buildconfig.BuildConfig `json:"buildConfig,omitempty" validate:"optional"` - RepositoryUrl string `json:"repositoryUrl" validate:"required"` - EnvVars map[string]string `json:"envVars" validate:"required"` - IsDefault bool `json:"default" validate:"required"` - Prebuilds []*PrebuildConfig `json:"prebuilds" validate:"optional"` - GitProviderConfigId *string `json:"gitProviderConfigId" validate:"optional"` -} // @name ProjectConfig - -func (pc *ProjectConfig) SetPrebuild(p *PrebuildConfig) error { - newPrebuild := PrebuildConfig{ - Id: p.Id, - Branch: p.Branch, - CommitInterval: p.CommitInterval, - TriggerFiles: p.TriggerFiles, - Retention: p.Retention, - } - - for _, pb := range pc.Prebuilds { - if pb.Id == p.Id { - *pb = newPrebuild - return nil - } - } - - pc.Prebuilds = append(pc.Prebuilds, &newPrebuild) - return nil -} - -func (pc *ProjectConfig) FindPrebuild(filter *PrebuildFilter) (*PrebuildConfig, error) { - for _, pb := range pc.Prebuilds { - if pb.Match(filter) { - return pb, nil - } - } - - return nil, errors.New("prebuild not found") -} - -func (pc *ProjectConfig) ListPrebuilds(filter *PrebuildFilter) ([]*PrebuildConfig, error) { - if filter == nil { - return pc.Prebuilds, nil - } - - prebuilds := []*PrebuildConfig{} - - for _, pb := range pc.Prebuilds { - if pb.Match(filter) { - prebuilds = append(prebuilds, pb) - } - } - - return prebuilds, nil -} - -func (pc *ProjectConfig) RemovePrebuild(id string) error { - newPrebuilds := []*PrebuildConfig{} - - for _, pb := range pc.Prebuilds { - if pb.Id != id { - newPrebuilds = append(newPrebuilds, pb) - } - } - - pc.Prebuilds = newPrebuilds - return nil -} diff --git a/pkg/workspace/project/config/prebuild.go b/pkg/workspace/project/config/prebuild.go deleted file mode 100644 index f4a7a50573..0000000000 --- a/pkg/workspace/project/config/prebuild.go +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package config - -import ( - "encoding/json" - "sort" - - "github.com/docker/docker/pkg/stringid" -) - -// PrebuildConfig holds configuration for the prebuild process -type PrebuildConfig struct { - Id string `json:"id" validate:"required"` - Branch string `json:"branch" validate:"required"` - CommitInterval *int `json:"commitInterval" validate:"required"` - TriggerFiles []string `json:"triggerFiles" validate:"required"` - Retention int `json:"retention" validate:"required"` -} // @name PrebuildConfig - -func (p *PrebuildConfig) GenerateId() error { - id := stringid.GenerateRandomID() - id = stringid.TruncateID(id) - - p.Id = id - return nil -} - -func (p *PrebuildConfig) Match(filter *PrebuildFilter) bool { - if filter.Id != nil && *filter.Id != p.Id { - return false - } - - if filter.Branch != nil && *filter.Branch != p.Branch { - return false - } - - if filter.CommitInterval != nil && p.CommitInterval != nil && *filter.CommitInterval != *p.CommitInterval { - return false - } - - if filter.TriggerFiles != nil { - // Sort the trigger files before checking if same - sort.Strings(p.TriggerFiles) - sort.Strings(*filter.TriggerFiles) - triggerFilesJson, err := json.Marshal(p.TriggerFiles) - if err != nil { - return false - } - filterFilesJson, err := json.Marshal(*filter.TriggerFiles) - if err != nil { - return false - } - if string(triggerFilesJson) != string(filterFilesJson) { - return false - } - } - - return true -} diff --git a/pkg/workspace/project/config/store.go b/pkg/workspace/project/config/store.go deleted file mode 100644 index 2cb788bed2..0000000000 --- a/pkg/workspace/project/config/store.go +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package config - -import "errors" - -type ProjectConfigFilter struct { - Name *string - Url *string - Default *bool - PrebuildId *string - GitProviderConfigId *string -} - -type PrebuildFilter struct { - ProjectConfigName *string - Id *string - Branch *string - CommitInterval *int - TriggerFiles *[]string -} - -type Store interface { - List(filter *ProjectConfigFilter) ([]*ProjectConfig, error) - Find(filter *ProjectConfigFilter) (*ProjectConfig, error) - Save(projectConfig *ProjectConfig) error - Delete(projectConfig *ProjectConfig) error -} - -var ( - ErrProjectConfigNotFound = errors.New("project config not found") - ErrPrebuildNotFound = errors.New("prebuild not found") -) - -func IsProjectConfigNotFound(err error) bool { - return err.Error() == ErrProjectConfigNotFound.Error() -} - -func IsPrebuildNotFound(err error) bool { - return err.Error() == ErrPrebuildNotFound.Error() -} diff --git a/pkg/workspace/project/containerconfig/config.go b/pkg/workspace/project/containerconfig/config.go deleted file mode 100644 index 04a73bbe7d..0000000000 --- a/pkg/workspace/project/containerconfig/config.go +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package containerconfig - -type ContainerConfig struct { - Image string `json:"image" validate:"required"` - User string `json:"user" validate:"required"` -} // @name ContainerConfig diff --git a/pkg/workspace/project/project.go b/pkg/workspace/project/project.go deleted file mode 100644 index c3505017b4..0000000000 --- a/pkg/workspace/project/project.go +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package project - -import ( - "fmt" - "strings" - - "github.com/daytonaio/daytona/pkg/gitprovider" - "github.com/daytonaio/daytona/pkg/workspace/project/buildconfig" -) - -type Project struct { - Name string `json:"name" validate:"required"` - Image string `json:"image" validate:"required"` - User string `json:"user" validate:"required"` - BuildConfig *buildconfig.BuildConfig `json:"buildConfig,omitempty" validate:"optional"` - Repository *gitprovider.GitRepository `json:"repository" validate:"required"` - EnvVars map[string]string `json:"envVars" validate:"required"` - WorkspaceId string `json:"workspaceId" validate:"required"` - ApiKey string `json:"-"` - Target string `json:"target" validate:"required"` - State *ProjectState `json:"state,omitempty" validate:"optional"` - GitProviderConfigId *string `json:"gitProviderConfigId,omitempty" validate:"optional"` -} // @name Project - -type ProjectInfo struct { - Name string `json:"name" validate:"required"` - Created string `json:"created" validate:"required"` - IsRunning bool `json:"isRunning" validate:"required"` - ProviderMetadata string `json:"providerMetadata,omitempty" validate:"optional"` - WorkspaceId string `json:"workspaceId" validate:"required"` -} // @name ProjectInfo - -type ProjectState struct { - UpdatedAt string `json:"updatedAt" validate:"required"` - Uptime uint64 `json:"uptime" validate:"required"` - GitStatus *GitStatus `json:"gitStatus" validate:"optional"` -} // @name ProjectState - -type GitStatus struct { - CurrentBranch string `json:"currentBranch" validate:"required"` - Files []*FileStatus `json:"fileStatus" validate:"required"` - BranchPublished bool `json:"branchPublished" validate:"optional"` - Ahead int `json:"ahead" validate:"optional"` - Behind int `json:"behind" validate:"optional"` -} // @name GitStatus - -type FileStatus struct { - Name string `json:"name" validate:"required"` - Extra string `json:"extra" validate:"required"` - Staging Status `json:"staging" validate:"required"` - Worktree Status `json:"worktree" validate:"required"` -} // @name FileStatus - -// Status status code of a file in the Worktree -type Status string // @name Status - -const ( - Unmodified Status = "Unmodified" - Untracked Status = "Untracked" - Modified Status = "Modified" - Added Status = "Added" - Deleted Status = "Deleted" - Renamed Status = "Renamed" - Copied Status = "Copied" - UpdatedButUnmerged Status = "Updated but unmerged" -) - -type ProjectEnvVarParams struct { - ApiUrl string - ServerUrl string - ServerVersion string - ClientId string -} - -func GetProjectEnvVars(project *Project, params ProjectEnvVarParams, telemetryEnabled bool) map[string]string { - envVars := map[string]string{ - "DAYTONA_WS_ID": project.WorkspaceId, - "DAYTONA_WS_PROJECT_NAME": project.Name, - "DAYTONA_WS_PROJECT_REPOSITORY_URL": project.Repository.Url, - "DAYTONA_SERVER_API_KEY": project.ApiKey, - "DAYTONA_SERVER_VERSION": params.ServerVersion, - "DAYTONA_SERVER_URL": params.ServerUrl, - "DAYTONA_SERVER_API_URL": params.ApiUrl, - "DAYTONA_CLIENT_ID": params.ClientId, - // (HOME) will be replaced at runtime - "DAYTONA_AGENT_LOG_FILE_PATH": "(HOME)/.daytona-agent.log", - } - - if telemetryEnabled { - envVars["DAYTONA_TELEMETRY_ENABLED"] = "true" - } - - return envVars -} - -func GetProjectHostname(workspaceId string, projectName string) string { - // Replace special chars with hyphen to form valid hostname - // String resulting in consecutive hyphens is also valid - projectName = strings.ReplaceAll(projectName, "_", "-") - projectName = strings.ReplaceAll(projectName, "*", "-") - projectName = strings.ReplaceAll(projectName, ".", "-") - - hostname := fmt.Sprintf("%s-%s", workspaceId, projectName) - - if len(hostname) > 63 { - return hostname[:63] - } - - return hostname -} diff --git a/pkg/workspace/store.go b/pkg/workspace/store.go deleted file mode 100644 index eeec232fa7..0000000000 --- a/pkg/workspace/store.go +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package workspace - -import "errors" - -type Store interface { - List() ([]*Workspace, error) - Find(idOrName string) (*Workspace, error) - Save(workspace *Workspace) error - Delete(workspace *Workspace) error -} - -var ( - ErrWorkspaceNotFound = errors.New("workspace not found") -) - -func IsWorkspaceNotFound(err error) bool { - return err.Error() == ErrWorkspaceNotFound.Error() -} diff --git a/pkg/workspace/workspace.go b/pkg/workspace/workspace.go deleted file mode 100644 index adf5e75108..0000000000 --- a/pkg/workspace/workspace.go +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2024 Daytona Platforms Inc. -// SPDX-License-Identifier: Apache-2.0 - -package workspace - -import ( - "errors" - - "github.com/daytonaio/daytona/pkg/workspace/project" -) - -type Workspace struct { - Id string `json:"id" validate:"required"` - Name string `json:"name" validate:"required"` - Projects []*project.Project `json:"projects" validate:"required"` - Target string `json:"target" validate:"required"` - ApiKey string `json:"-"` - EnvVars map[string]string `json:"-"` -} // @name Workspace - -type WorkspaceInfo struct { - Name string `json:"name" validate:"required"` - Projects []*project.ProjectInfo `json:"projects" validate:"required"` - ProviderMetadata string `json:"providerMetadata,omitempty" validate:"optional"` -} // @name WorkspaceInfo - -func (w *Workspace) GetProject(projectName string) (*project.Project, error) { - for _, project := range w.Projects { - if project.Name == projectName { - return project, nil - } - } - return nil, errors.New("project not found") -} - -type WorkspaceEnvVarParams struct { - ApiUrl string - ServerUrl string - ServerVersion string - ClientId string -} - -func GetWorkspaceEnvVars(workspace *Workspace, params WorkspaceEnvVarParams, telemetryEnabled bool) map[string]string { - envVars := map[string]string{ - "DAYTONA_WS_ID": workspace.Id, - "DAYTONA_SERVER_API_KEY": workspace.ApiKey, - "DAYTONA_SERVER_VERSION": params.ServerVersion, - "DAYTONA_SERVER_URL": params.ServerUrl, - "DAYTONA_SERVER_API_URL": params.ApiUrl, - "DAYTONA_CLIENT_ID": params.ClientId, - // (HOME) will be replaced at runtime - "DAYTONA_AGENT_LOG_FILE_PATH": "(HOME)/.daytona-agent.log", - } - - if telemetryEnabled { - envVars["DAYTONA_TELEMETRY_ENABLED"] = "true" - } - - return envVars -}