mirror of
https://github.com/railwayapp/cli
synced 2026-04-21 14:07:23 +00:00
Remove personal team
This commit is contained in:
parent
9d65bd3f49
commit
155e0bc719
13 changed files with 20 additions and 205 deletions
|
|
@ -34,7 +34,6 @@ pub async fn command(args: Args, _json: bool) -> Result<()> {
|
|||
|
||||
let team_id = match team {
|
||||
Team::Team(team) => Some(team.id.clone()),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let vars = mutations::project_create::Variables {
|
||||
|
|
@ -84,18 +83,17 @@ pub async fn command(args: Args, _json: bool) -> Result<()> {
|
|||
}
|
||||
|
||||
fn get_team_names(teams: Vec<&UserProjectsMeTeamsEdgesNode>) -> Vec<Team> {
|
||||
let mut team_names = teams
|
||||
let team_names = teams
|
||||
.iter()
|
||||
.map(|team| Team::Team(team))
|
||||
.collect::<Vec<_>>();
|
||||
team_names.insert(0, Team::Personal);
|
||||
team_names
|
||||
}
|
||||
|
||||
fn prompt_team(teams: Vec<Team>) -> Result<Team> {
|
||||
// If there is only the personal team, return None
|
||||
if teams.len() == 1 {
|
||||
return Ok(Team::Personal);
|
||||
return Ok(teams[0].clone());
|
||||
}
|
||||
let team = prompt_select("Team", teams)?;
|
||||
Ok(team)
|
||||
|
|
@ -132,14 +130,12 @@ fn prompt_project_name() -> Result<String> {
|
|||
#[derive(Debug, Clone)]
|
||||
enum Team<'a> {
|
||||
Team(&'a UserProjectsMeTeamsEdgesNode),
|
||||
Personal,
|
||||
}
|
||||
|
||||
impl Display for Team<'_> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Team::Team(team) => write!(f, "{}", team.name),
|
||||
Team::Personal => write!(f, "{}", "Personal".bold()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,8 +9,7 @@ use crate::{
|
|||
|
||||
use super::{
|
||||
queries::user_projects::{
|
||||
UserProjectsMeProjectsEdgesNode, UserProjectsMeTeamsEdgesNode,
|
||||
UserProjectsMeTeamsEdgesNodeProjectsEdgesNode,
|
||||
UserProjectsMeTeamsEdgesNode, UserProjectsMeTeamsEdgesNodeProjectsEdgesNode,
|
||||
},
|
||||
*,
|
||||
};
|
||||
|
|
@ -50,7 +49,7 @@ pub async fn command(args: Args, _json: bool) -> Result<()> {
|
|||
|
||||
let team = select_team(args.project.clone(), args.team, &me)?;
|
||||
|
||||
let project = select_project(team, args.project.clone(), &me)?;
|
||||
let project = select_project(team, args.project.clone())?;
|
||||
|
||||
let environment = select_environment(args.environment, &project)?;
|
||||
|
||||
|
|
@ -145,25 +144,8 @@ fn select_environment(
|
|||
fn select_project(
|
||||
team: Team<'_>,
|
||||
project: Option<String>,
|
||||
me: &queries::user_projects::UserProjectsMe,
|
||||
) -> Result<NormalisedProject, anyhow::Error> {
|
||||
let project = NormalisedProject::from(match team {
|
||||
Team::Personal => {
|
||||
if let Some(project) = project {
|
||||
let proj = me.projects.edges.iter().find(|pro| {
|
||||
(pro.node.id.to_lowercase() == project.to_lowercase())
|
||||
|| (pro.node.name.to_lowercase() == project.to_lowercase())
|
||||
});
|
||||
if let Some(project) = proj {
|
||||
fake_select("Select a project", &project.node.name);
|
||||
Project(ProjectType::Personal(project.node.clone()))
|
||||
} else {
|
||||
return Err(RailwayError::ProjectNotFound.into());
|
||||
}
|
||||
} else {
|
||||
prompt_personal_projects(me)?
|
||||
}
|
||||
}
|
||||
Team::Team(team) => {
|
||||
if let Some(project) = project {
|
||||
let proj = team.projects.edges.iter().find(|pro| {
|
||||
|
|
@ -197,15 +179,7 @@ fn select_team(
|
|||
let team = match (project.as_ref(), team.as_ref()) {
|
||||
(Some(project), None) if uuid_regex.is_match(project) => {
|
||||
// It's a project id, figure out team
|
||||
if me
|
||||
.projects
|
||||
.edges
|
||||
.iter()
|
||||
.any(|pro| pro.node.id.to_lowercase() == project.to_lowercase())
|
||||
{
|
||||
fake_select("Select a team", "Personal");
|
||||
Team::Personal
|
||||
} else if let Some(team) = me.teams.edges.iter().find(|team| {
|
||||
if let Some(team) = me.teams.edges.iter().find(|team| {
|
||||
team.node
|
||||
.projects
|
||||
.edges
|
||||
|
|
@ -218,32 +192,16 @@ fn select_team(
|
|||
return Err(RailwayError::ProjectNotFound.into());
|
||||
}
|
||||
}
|
||||
(Some(project), None) => {
|
||||
(Some(_), None) => {
|
||||
// this means project name without team
|
||||
if me.teams.edges.is_empty() {
|
||||
// no teams, so it's personal
|
||||
// if there is a project that has the same name
|
||||
if me
|
||||
.projects
|
||||
.edges
|
||||
.iter()
|
||||
.any(|p| p.node.name.to_lowercase() == project.to_lowercase())
|
||||
{
|
||||
fake_select("Select a team", "Personal");
|
||||
Team::Personal
|
||||
} else {
|
||||
return Err(RailwayError::ProjectNotFound.into());
|
||||
}
|
||||
return Err(RailwayError::ProjectNotFound.into());
|
||||
} else {
|
||||
prompt_teams(me)?
|
||||
}
|
||||
}
|
||||
(None, Some(team_arg)) | (Some(_), Some(team_arg)) => {
|
||||
match team_arg.to_lowercase().as_str() {
|
||||
"personal" => {
|
||||
fake_select("Select a team", "Personal");
|
||||
Team::Personal
|
||||
}
|
||||
_ => {
|
||||
if let Some(team) = me.teams.edges.iter().find(|team| {
|
||||
(team.node.name.to_lowercase() == team_arg.to_lowercase())
|
||||
|
|
@ -258,10 +216,7 @@ fn select_team(
|
|||
}
|
||||
}
|
||||
(None, None) if !me.teams.edges.is_empty() => prompt_teams(me)?,
|
||||
(None, None) => {
|
||||
fake_select("Select a team", "Personal");
|
||||
Team::Personal
|
||||
}
|
||||
(None, None) => return Err(RailwayError::NoWorkspaceFound.into()),
|
||||
};
|
||||
Ok(team)
|
||||
}
|
||||
|
|
@ -269,7 +224,7 @@ fn select_team(
|
|||
fn prompt_teams(me: &queries::user_projects::UserProjectsMe) -> Result<Team<'_>> {
|
||||
let teams: Vec<&UserProjectsMeTeamsEdgesNode> =
|
||||
me.teams.edges.iter().map(|team| &team.node).collect();
|
||||
let mut team_names = vec![Team::Personal];
|
||||
let mut team_names = vec![];
|
||||
team_names.extend(teams.into_iter().map(Team::Team));
|
||||
prompt_options("Select a team", team_names)
|
||||
}
|
||||
|
|
@ -294,27 +249,6 @@ fn prompt_team_projects(
|
|||
prompt_options("Select a project", prompt_projects)
|
||||
}
|
||||
|
||||
fn prompt_personal_projects(
|
||||
me: &queries::user_projects::UserProjectsMe,
|
||||
) -> Result<Project, anyhow::Error> {
|
||||
let mut personal_projects = me
|
||||
.projects
|
||||
.edges
|
||||
.iter()
|
||||
.map(|project| &project.node)
|
||||
.collect::<Vec<&UserProjectsMeProjectsEdgesNode>>();
|
||||
if personal_projects.is_empty() {
|
||||
return Err(RailwayError::NoProjects.into());
|
||||
}
|
||||
personal_projects.sort_by(|a, b| b.updated_at.cmp(&a.updated_at));
|
||||
let prompt_projects = personal_projects
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(|project| Project(ProjectType::Personal(project.clone())))
|
||||
.collect::<Vec<Project>>();
|
||||
prompt_options("Select a project", prompt_projects)
|
||||
}
|
||||
|
||||
structstruck::strike! {
|
||||
#[strikethrough[derive(Debug, Clone, derive_new::new)]]
|
||||
struct NormalisedProject {
|
||||
|
|
@ -348,34 +282,6 @@ structstruck::strike! {
|
|||
impl From<Project> for NormalisedProject {
|
||||
fn from(value: Project) -> Self {
|
||||
match value.0 {
|
||||
ProjectType::Personal(personal) => NormalisedProject::new(
|
||||
personal.id,
|
||||
personal.name,
|
||||
personal
|
||||
.environments
|
||||
.edges
|
||||
.into_iter()
|
||||
.map(|env| NormalisedEnvironment::new(env.node.id, env.node.name))
|
||||
.collect(),
|
||||
personal
|
||||
.services
|
||||
.edges
|
||||
.into_iter()
|
||||
.map(|service| {
|
||||
NormalisedService::new(
|
||||
service.node.id,
|
||||
service.node.name,
|
||||
service
|
||||
.node
|
||||
.service_instances
|
||||
.edges
|
||||
.into_iter()
|
||||
.map(|instance| instance.node.environment_id)
|
||||
.collect(),
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
),
|
||||
ProjectType::Team(team) => NormalisedProject::new(
|
||||
team.id,
|
||||
team.name,
|
||||
|
|
@ -409,21 +315,18 @@ impl From<Project> for NormalisedProject {
|
|||
#[derive(Debug, Clone)]
|
||||
enum Team<'a> {
|
||||
Team(&'a UserProjectsMeTeamsEdgesNode),
|
||||
Personal,
|
||||
}
|
||||
|
||||
impl Display for Team<'_> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Team::Team(team) => write!(f, "{}", team.name),
|
||||
Team::Personal => write!(f, "{}", "Personal".bold()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
enum ProjectType {
|
||||
Personal(UserProjectsMeProjectsEdgesNode),
|
||||
Team(UserProjectsMeTeamsEdgesNodeProjectsEdgesNode),
|
||||
}
|
||||
|
||||
|
|
@ -433,7 +336,6 @@ struct Project(ProjectType);
|
|||
impl Display for Project {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match &self.0 {
|
||||
ProjectType::Personal(personal) => write!(f, "{}", personal.name),
|
||||
ProjectType::Team(team_project) => write!(f, "{}", team_project.name),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,6 @@
|
|||
use serde::Serialize;
|
||||
|
||||
use super::{
|
||||
queries::{
|
||||
projects::ProjectsProjectsEdgesNode, user_projects::UserProjectsMeProjectsEdgesNode,
|
||||
},
|
||||
*,
|
||||
};
|
||||
use super::{queries::projects::ProjectsProjectsEdgesNode, *};
|
||||
|
||||
/// List all projects in your Railway account
|
||||
#[derive(Parser)]
|
||||
|
|
@ -21,35 +16,9 @@ pub async fn command(_args: Args, json: bool) -> Result<()> {
|
|||
.await?
|
||||
.me;
|
||||
|
||||
let mut personal_projects: Vec<_> = me
|
||||
.projects
|
||||
.edges
|
||||
.iter()
|
||||
.map(|project| &project.node)
|
||||
.collect();
|
||||
// Sort by most recently updated (matches dashboard behavior)
|
||||
personal_projects.sort_by(|a, b| b.updated_at.cmp(&a.updated_at));
|
||||
|
||||
let mut all_projects: Vec<_> = personal_projects
|
||||
.iter()
|
||||
.map(|project| Project::Me((*project).clone()))
|
||||
.collect();
|
||||
let mut all_projects: Vec<_> = vec![];
|
||||
|
||||
let teams: Vec<_> = me.teams.edges.iter().map(|team| &team.node).collect();
|
||||
if !json {
|
||||
println!("{}", "Personal".bold());
|
||||
for project in &personal_projects {
|
||||
let project_name = if linked_project.is_some()
|
||||
&& project.id == linked_project.as_ref().unwrap().project
|
||||
{
|
||||
project.name.purple().bold()
|
||||
} else {
|
||||
project.name.white()
|
||||
};
|
||||
println!(" {project_name}");
|
||||
}
|
||||
}
|
||||
|
||||
for team in teams {
|
||||
if !json {
|
||||
println!();
|
||||
|
|
@ -95,6 +64,5 @@ pub async fn command(_args: Args, json: bool) -> Result<()> {
|
|||
#[derive(Debug, Clone, Serialize)]
|
||||
#[serde(untagged)]
|
||||
enum Project {
|
||||
Me(UserProjectsMeProjectsEdgesNode),
|
||||
Team(ProjectsProjectsEdgesNode),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// src/commands/ssh/common.rs
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use anyhow::{anyhow, Result};
|
||||
use indicatif::{ProgressBar, ProgressStyle};
|
||||
use reqwest::Client;
|
||||
use tokio::time::Duration;
|
||||
|
|
@ -113,7 +113,6 @@ pub async fn establish_connection(
|
|||
ws_url: &str,
|
||||
token: &str,
|
||||
params: &SSHConnectParams,
|
||||
spinner: &ProgressBar,
|
||||
) -> Result<TerminalClient> {
|
||||
let mut client = TerminalClient::new(ws_url, token, params).await?;
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ use clap::Parser;
|
|||
|
||||
use crate::client::GQLClient;
|
||||
use crate::config::Configs;
|
||||
use crate::controllers::terminal::SSHConnectParams;
|
||||
|
||||
pub const SSH_CONNECTION_TIMEOUT_SECS: u64 = 30;
|
||||
pub const SSH_MESSAGE_TIMEOUT_SECS: u64 = 10;
|
||||
|
|
@ -58,7 +57,7 @@ pub async fn command(args: Args, _json: bool) -> Result<()> {
|
|||
let spinner = create_spinner(running_command);
|
||||
|
||||
let ws_url = format!("wss://{}", configs.get_relay_host_path());
|
||||
let mut terminal_client = establish_connection(&ws_url, &token, ¶ms, &spinner).await?;
|
||||
let mut terminal_client = establish_connection(&ws_url, &token, ¶ms).await?;
|
||||
|
||||
if running_command {
|
||||
// Run single command
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
use anyhow::Result;
|
||||
use crossterm::terminal;
|
||||
use futures_util::FutureExt;
|
||||
use tokio::io::AsyncReadExt;
|
||||
use tokio::select;
|
||||
|
||||
|
|
|
|||
|
|
@ -4,14 +4,13 @@ use std::{
|
|||
time::Duration,
|
||||
};
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
use anyhow::Result;
|
||||
|
||||
use futures::StreamExt;
|
||||
use gzp::{deflate::Gzip, ZBuilder};
|
||||
use ignore::WalkBuilder;
|
||||
use indicatif::{ProgressBar, ProgressFinish, ProgressIterator, ProgressStyle};
|
||||
use is_terminal::IsTerminal;
|
||||
use reqwest::Client;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use synchronized_writer::SynchronizedWriter;
|
||||
use tar::Builder;
|
||||
|
|
@ -21,7 +20,7 @@ use crate::{
|
|||
controllers::{
|
||||
deployment::{stream_build_logs, stream_deploy_logs},
|
||||
environment::get_matched_environment,
|
||||
project::{ensure_project_and_environment_exist, get_project},
|
||||
project::get_project,
|
||||
service::get_or_prompt_service,
|
||||
},
|
||||
errors::RailwayError,
|
||||
|
|
@ -29,7 +28,6 @@ use crate::{
|
|||
subscriptions::deployment::DeploymentStatus,
|
||||
util::{
|
||||
logs::format_attr_log,
|
||||
prompt::{prompt_select, PromptService},
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -69,12 +69,6 @@ struct GithubApiRelease {
|
|||
|
||||
const GITHUB_API_RELEASE_URL: &str = "https://api.github.com/repos/railwayapp/cli/releases/latest";
|
||||
|
||||
pub const SSH_CONNECTION_TIMEOUT_SECS: u64 = 10;
|
||||
pub const SSH_MESSAGE_TIMEOUT_SECS: u64 = 5;
|
||||
pub const SSH_RECONNECT_DELAY_SECS: u64 = 1;
|
||||
pub const SSH_MAX_RECONNECT_ATTEMPTS: u32 = 3;
|
||||
pub const SSH_MAX_EMPTY_MESSAGES: u32 = 5;
|
||||
|
||||
impl Configs {
|
||||
pub fn new() -> Result<Self> {
|
||||
let environment = Self::get_environment_id();
|
||||
|
|
|
|||
|
|
@ -169,7 +169,6 @@ impl TerminalClient {
|
|||
/// Process incoming messages from the server
|
||||
pub async fn handle_server_messages(&mut self) -> Result<()> {
|
||||
let mut consecutive_empty_messages = 0;
|
||||
let mut exit_code: Option<i32> = None;
|
||||
|
||||
let mut ping_interval = interval(Duration::from_secs(SSH_PING_INTERVAL_SECS));
|
||||
|
||||
|
|
|
|||
|
|
@ -2,12 +2,11 @@ use anyhow::{bail, Result};
|
|||
use async_tungstenite::tungstenite::handshake::client::generate_key;
|
||||
use async_tungstenite::tungstenite::http::Request;
|
||||
use async_tungstenite::WebSocketStream;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tokio::time::{sleep, timeout, Duration};
|
||||
use url::Url;
|
||||
|
||||
use crate::commands::ssh::{
|
||||
SSH_CONNECTION_TIMEOUT_SECS, SSH_MAX_RECONNECT_ATTEMPTS, SSH_MESSAGE_TIMEOUT_SECS,
|
||||
SSH_CONNECTION_TIMEOUT_SECS, SSH_MAX_RECONNECT_ATTEMPTS,
|
||||
SSH_RECONNECT_DELAY_SECS,
|
||||
};
|
||||
use crate::consts::get_user_agent;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ mod connection;
|
|||
mod messages;
|
||||
|
||||
pub use client::TerminalClient;
|
||||
pub use connection::{attempt_connection, establish_connection, SSHConnectParams};
|
||||
pub use messages::{ClientMessage, ClientPayload, DataPayload, ServerMessage, ServerPayload};
|
||||
pub use connection::SSHConnectParams;
|
||||
|
||||
pub const SSH_PING_INTERVAL_SECS: u64 = 10;
|
||||
|
|
|
|||
|
|
@ -33,9 +33,6 @@ pub enum RailwayError {
|
|||
#[error("Environment is deleted. Run `railway environment` to connect to an environment.")]
|
||||
EnvironmentDeleted,
|
||||
|
||||
#[error("No projects found. Run `railway init` to create a new project")]
|
||||
NoProjects,
|
||||
|
||||
#[error("Project does not have any services")]
|
||||
NoServices,
|
||||
|
||||
|
|
@ -50,6 +47,9 @@ pub enum RailwayError {
|
|||
#[error("Service \"{0}\" not found.\nRun `railway service` to connect to a service.")]
|
||||
ServiceNotFound(String),
|
||||
|
||||
#[error("No workspace found.")]
|
||||
NoWorkspaceFound,
|
||||
|
||||
#[error("Team \"{0}\" not found.")]
|
||||
TeamNotFound(String),
|
||||
|
||||
|
|
|
|||
|
|
@ -1,42 +1,5 @@
|
|||
query UserProjects {
|
||||
me {
|
||||
projects {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
name
|
||||
createdAt
|
||||
updatedAt
|
||||
team {
|
||||
id
|
||||
name
|
||||
}
|
||||
environments {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
services {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
name
|
||||
serviceInstances {
|
||||
edges {
|
||||
node {
|
||||
environmentId
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
teams {
|
||||
edges {
|
||||
node {
|
||||
|
|
|
|||
Loading…
Reference in a new issue