Skip to content

Commit

Permalink
feat: Fetch templates from a GraphQL API
Browse files Browse the repository at this point in the history
  • Loading branch information
dbanty committed Oct 25, 2022
1 parent b73dfb3 commit 622358a
Show file tree
Hide file tree
Showing 16 changed files with 467 additions and 231 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,7 @@ node_modules
# and rover devs may want to have one local to the rover repo
# for testing purposes, though it should not be committed
# (unless we start using .apollo to configure our schema fetching for rover-client)
.apollo
.apollo

# JetBrains IDEs
.idea
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ crossterm = { workspace = true }
ctrlc = { workspace = true }
dialoguer = { workspace = true }
flate2 = { workspace = true }
graphql_client = { workspace = true }
heck = { workspace = true }
houston = { workspace = true }
interprocess = { workspace = true }
Expand Down
3 changes: 0 additions & 3 deletions rust-toolchain.toml

This file was deleted.

2 changes: 1 addition & 1 deletion src/command/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ pub(crate) mod install;
mod readme;
pub(crate) mod subgraph;
mod supergraph;
mod template;
pub(crate) mod template;
mod update;

pub(crate) mod output;
Expand Down
22 changes: 12 additions & 10 deletions src/command/output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ use crate::error::RoverError;
use crate::utils::color::Style;
use crate::utils::table::{self, row};

use crate::options::GithubTemplate;
use crate::command::template::queries::list_templates_for_language::ListTemplatesForLanguageTemplates;
use crate::options::ProjectLanguage;
use atty::Stream;
use calm_io::{stderr, stderrln, stdout, stdoutln};
use crossterm::style::Attribute::Underlined;
Expand Down Expand Up @@ -56,9 +57,9 @@ pub enum RoverOutput {
dry_run: bool,
delete_response: SubgraphDeleteResponse,
},
TemplateList(Vec<GithubTemplate>),
TemplateList(Vec<ListTemplatesForLanguageTemplates>),
TemplateUseSuccess {
template: GithubTemplate,
template_id: String,
path: Utf8PathBuf,
},
Profiles(Vec<String>),
Expand Down Expand Up @@ -255,21 +256,22 @@ impl RoverOutput {
table.add_row(row![bc => "Name", "ID", "Language", "Repo URL"]);

for template in templates {
let language: ProjectLanguage = template.language.clone().into();
table.add_row(row![
template.display,
template.name,
template.id,
template.language,
template.git_url
language,
template.repo_url,
]);
}

stdoutln!("{}", table)?;
}
RoverOutput::TemplateUseSuccess { template, path } => {
RoverOutput::TemplateUseSuccess { template_id, path } => {
print_descriptor("Project generated")?;
stdoutln!(
"Successfully created a new project from the '{template_id}' template in {path}",
template_id = Style::Command.paint(template.id),
template_id = Style::Command.paint(template_id),
path = Style::Path.paint(path.as_str())
)?;
stdoutln!(
Expand Down Expand Up @@ -382,8 +384,8 @@ impl RoverOutput {
}
RoverOutput::SubgraphList(list_response) => json!(list_response),
RoverOutput::TemplateList(templates) => json!({ "templates": templates }),
RoverOutput::TemplateUseSuccess { template, path } => {
json!({ "template_id": template.id, "path": path })
RoverOutput::TemplateUseSuccess { template_id, path } => {
json!({ "template_id": template_id, "path": path })
}
RoverOutput::CheckResponse(check_response) => check_response.get_json(),
RoverOutput::AsyncCheckResponse(check_response) => check_response.get_json(),
Expand Down
2 changes: 2 additions & 0 deletions src/command/template/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.graphqlconfig
schema.graphql
1 change: 1 addition & 0 deletions src/command/template/custom_scalars.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub(super) use url::Url;
9 changes: 3 additions & 6 deletions src/command/template/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use serde::Serialize;
use crate::options::TemplateOpt;
use crate::{command::RoverOutput, Result};

use super::templates::GithubTemplates;
use super::templates::list_templates;

#[derive(Clone, Debug, Parser, Serialize)]
pub struct List {
Expand All @@ -14,10 +14,7 @@ pub struct List {

impl List {
pub fn run(&self) -> Result<RoverOutput> {
let mut templates = GithubTemplates::new();
if let Some(project_language) = self.options.language {
templates = templates.filter_language(project_language);
}
Ok(RoverOutput::TemplateList(templates.values()?))
let templates = list_templates(self.options.language.clone())?;
Ok(RoverOutput::TemplateList(templates))
}
}
3 changes: 2 additions & 1 deletion src/command/template/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
pub(crate) mod custom_scalars;
mod list;
pub(crate) mod queries;
mod templates;
mod r#use;

Expand All @@ -8,7 +10,6 @@ pub use r#use::Use;
use saucer::{clap, Parser};
use serde::Serialize;

use crate::options::GithubTemplate;
use crate::utils::client::StudioClientConfig;
use crate::{command::RoverOutput, Result};

Expand Down
23 changes: 23 additions & 0 deletions src/command/template/queries.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
query ListTemplatesForLanguage($language: Language) {
templates(language: $language) {
id
name
description
repoUrl
language
}
}

query GetTemplateById($id: ID!) {
template(id: $id) {
downloadUrl
}
}

query GetTemplatesForLanguage($language: Language) {
templates(language: $language) {
id
name
downloadUrl
}
}
216 changes: 216 additions & 0 deletions src/command/template/queries.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
#![allow(clippy::all, warnings)]
pub struct ListTemplatesForLanguage;
pub mod list_templates_for_language {
#![allow(dead_code)]
use std::result::Result;
pub const OPERATION_NAME: &str = "ListTemplatesForLanguage";
pub const QUERY : & str = "query ListTemplatesForLanguage($language: Language) {\n templates(language: $language) {\n id\n name\n description\n repoUrl\n language\n }\n}\n\nquery GetTemplateById($id: ID!) {\n template(id: $id) {\n downloadUrl\n }\n}\n\nquery GetTemplatesForLanguage($language: Language) {\n templates(language: $language) {\n id\n name\n downloadUrl\n }\n}" ;
use super::*;
use serde::{Deserialize, Serialize};
#[allow(dead_code)]
type Boolean = bool;
#[allow(dead_code)]
type Float = f64;
#[allow(dead_code)]
type Int = i64;
#[allow(dead_code)]
type ID = String;
type Url = crate::command::template::custom_scalars::Url;
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Language {
GO,
JAVA,
JAVASCRIPT,
KOTLIN,
PYTHON,
RUST,
TYPESCRIPT,
Other(String),
}
impl ::serde::Serialize for Language {
fn serialize<S: serde::Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
ser.serialize_str(match *self {
Language::GO => "GO",
Language::JAVA => "JAVA",
Language::JAVASCRIPT => "JAVASCRIPT",
Language::KOTLIN => "KOTLIN",
Language::PYTHON => "PYTHON",
Language::RUST => "RUST",
Language::TYPESCRIPT => "TYPESCRIPT",
Language::Other(ref s) => &s,
})
}
}
impl<'de> ::serde::Deserialize<'de> for Language {
fn deserialize<D: ::serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let s: String = ::serde::Deserialize::deserialize(deserializer)?;
match s.as_str() {
"GO" => Ok(Language::GO),
"JAVA" => Ok(Language::JAVA),
"JAVASCRIPT" => Ok(Language::JAVASCRIPT),
"KOTLIN" => Ok(Language::KOTLIN),
"PYTHON" => Ok(Language::PYTHON),
"RUST" => Ok(Language::RUST),
"TYPESCRIPT" => Ok(Language::TYPESCRIPT),
_ => Ok(Language::Other(s)),
}
}
}
#[derive(Serialize)]
pub struct Variables {
pub language: Option<Language>,
}
impl Variables {}
#[derive(Deserialize, Debug, Serialize, PartialEq, Eq, Clone)]
pub struct ResponseData {
pub templates: Vec<ListTemplatesForLanguageTemplates>,
}
#[derive(Deserialize, Debug, Serialize, PartialEq, Eq, Clone)]
pub struct ListTemplatesForLanguageTemplates {
pub id: ID,
pub name: String,
pub description: String,
#[serde(rename = "repoUrl")]
pub repo_url: Url,
pub language: Language,
}
}
impl graphql_client::GraphQLQuery for ListTemplatesForLanguage {
type Variables = list_templates_for_language::Variables;
type ResponseData = list_templates_for_language::ResponseData;
fn build_query(variables: Self::Variables) -> ::graphql_client::QueryBody<Self::Variables> {
graphql_client::QueryBody {
variables,
query: list_templates_for_language::QUERY,
operation_name: list_templates_for_language::OPERATION_NAME,
}
}
}
pub struct GetTemplateById;
pub mod get_template_by_id {
#![allow(dead_code)]
use std::result::Result;
pub const OPERATION_NAME: &str = "GetTemplateById";
pub const QUERY : & str = "query ListTemplatesForLanguage($language: Language) {\n templates(language: $language) {\n id\n name\n description\n repoUrl\n language\n }\n}\n\nquery GetTemplateById($id: ID!) {\n template(id: $id) {\n downloadUrl\n }\n}\n\nquery GetTemplatesForLanguage($language: Language) {\n templates(language: $language) {\n id\n name\n downloadUrl\n }\n}" ;
use super::*;
use serde::{Deserialize, Serialize};
#[allow(dead_code)]
type Boolean = bool;
#[allow(dead_code)]
type Float = f64;
#[allow(dead_code)]
type Int = i64;
#[allow(dead_code)]
type ID = String;
type Url = crate::command::template::custom_scalars::Url;
#[derive(Serialize)]
pub struct Variables {
pub id: ID,
}
impl Variables {}
#[derive(Deserialize, Debug, Serialize, PartialEq, Eq, Clone)]
pub struct ResponseData {
pub template: Option<GetTemplateByIdTemplate>,
}
#[derive(Deserialize, Debug, Serialize, PartialEq, Eq, Clone)]
pub struct GetTemplateByIdTemplate {
#[serde(rename = "downloadUrl")]
pub download_url: Url,
}
}
impl graphql_client::GraphQLQuery for GetTemplateById {
type Variables = get_template_by_id::Variables;
type ResponseData = get_template_by_id::ResponseData;
fn build_query(variables: Self::Variables) -> ::graphql_client::QueryBody<Self::Variables> {
graphql_client::QueryBody {
variables,
query: get_template_by_id::QUERY,
operation_name: get_template_by_id::OPERATION_NAME,
}
}
}
pub struct GetTemplatesForLanguage;
pub mod get_templates_for_language {
#![allow(dead_code)]
use std::result::Result;
pub const OPERATION_NAME: &str = "GetTemplatesForLanguage";
pub const QUERY : & str = "query ListTemplatesForLanguage($language: Language) {\n templates(language: $language) {\n id\n name\n description\n repoUrl\n language\n }\n}\n\nquery GetTemplateById($id: ID!) {\n template(id: $id) {\n downloadUrl\n }\n}\n\nquery GetTemplatesForLanguage($language: Language) {\n templates(language: $language) {\n id\n name\n downloadUrl\n }\n}" ;
use super::*;
use serde::{Deserialize, Serialize};
#[allow(dead_code)]
type Boolean = bool;
#[allow(dead_code)]
type Float = f64;
#[allow(dead_code)]
type Int = i64;
#[allow(dead_code)]
type ID = String;
type Url = crate::command::template::custom_scalars::Url;
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Language {
GO,
JAVA,
JAVASCRIPT,
KOTLIN,
PYTHON,
RUST,
TYPESCRIPT,
Other(String),
}
impl ::serde::Serialize for Language {
fn serialize<S: serde::Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
ser.serialize_str(match *self {
Language::GO => "GO",
Language::JAVA => "JAVA",
Language::JAVASCRIPT => "JAVASCRIPT",
Language::KOTLIN => "KOTLIN",
Language::PYTHON => "PYTHON",
Language::RUST => "RUST",
Language::TYPESCRIPT => "TYPESCRIPT",
Language::Other(ref s) => &s,
})
}
}
impl<'de> ::serde::Deserialize<'de> for Language {
fn deserialize<D: ::serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let s: String = ::serde::Deserialize::deserialize(deserializer)?;
match s.as_str() {
"GO" => Ok(Language::GO),
"JAVA" => Ok(Language::JAVA),
"JAVASCRIPT" => Ok(Language::JAVASCRIPT),
"KOTLIN" => Ok(Language::KOTLIN),
"PYTHON" => Ok(Language::PYTHON),
"RUST" => Ok(Language::RUST),
"TYPESCRIPT" => Ok(Language::TYPESCRIPT),
_ => Ok(Language::Other(s)),
}
}
}
#[derive(Serialize)]
pub struct Variables {
pub language: Option<Language>,
}
impl Variables {}
#[derive(Deserialize, Debug, Serialize, PartialEq, Eq, Clone)]
pub struct ResponseData {
pub templates: Vec<GetTemplatesForLanguageTemplates>,
}
#[derive(Deserialize, Debug, Serialize, PartialEq, Eq, Clone)]
pub struct GetTemplatesForLanguageTemplates {
pub id: ID,
pub name: String,
#[serde(rename = "downloadUrl")]
pub download_url: Url,
}
}
impl graphql_client::GraphQLQuery for GetTemplatesForLanguage {
type Variables = get_templates_for_language::Variables;
type ResponseData = get_templates_for_language::ResponseData;
fn build_query(variables: Self::Variables) -> ::graphql_client::QueryBody<Self::Variables> {
graphql_client::QueryBody {
variables,
query: get_templates_for_language::QUERY,
operation_name: get_templates_for_language::OPERATION_NAME,
}
}
}
8 changes: 8 additions & 0 deletions src/command/template/regenerate_queries.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/usr/bin/env bash

set -euo pipefail

# Install this CLI with `cargo install graphql_client_cli`
graphql-client generate --schema-path schema.graphql queries.graphql \
--response-derives 'Debug,Serialize,PartialEq,Eq,Clone' \
--custom-scalars-module crate::command::template::custom_scalars
Loading

0 comments on commit 622358a

Please sign in to comment.