Add --latest flag to logs cmd and activeDeployments to status (#719)

* Add --latest flag to logs cmd and activeDeployments to status

- Add --latest flag to logs command to always show logs from the latest deployment even if failed/building
- Add activeDeployments field to Project query for status --json output
- Regenerate schema.json from Railway API

* Add .gitattributes to collapse schema.json in diffs
This commit is contained in:
Jake Runzer 2026-01-07 01:32:42 -05:00 committed by GitHub
parent d701e66e5f
commit 3e1455e1fa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 832 additions and 19 deletions

1
.gitattributes vendored Normal file
View file

@ -0,0 +1 @@
src/gql/schema.json linguist-generated=true

View file

@ -27,7 +27,8 @@ use super::{
railway logs --service backend --environment production # Stream latest deployment logs from a specific service in a specific environment
railway logs --lines 10 --filter \"@level:error\" # View 10 latest error logs
railway logs --lines 10 --filter \"@level:warn AND rate limit\" # View 10 latest warning logs related to rate limiting
railway logs --json # Get logs in JSON format"
railway logs --json # Get logs in JSON format
railway logs --latest # Stream logs from the latest deployment (even if failed/building)"
)]
pub struct Args {
/// Service to view logs from (defaults to linked service). Can be service name or service ID
@ -62,6 +63,10 @@ pub struct Args {
/// Can be a text search ("error message" or "user signup"), attribute filters (@level:error, @level:warn), or a combination with the operators AND, OR, - (not). See https://docs.railway.com/guides/logs for full syntax.
#[clap(long, short = 'f')]
filter: Option<String>,
/// Always show logs from the latest deployment, even if it failed or is still building
#[clap(long)]
latest: bool,
}
pub async fn command(args: Args) -> Result<()> {
@ -123,11 +128,15 @@ pub async fn command(args: Args) -> Result<()> {
.map(|deployment| deployment.node)
.collect();
all_deployments.sort_by(|a, b| b.created_at.cmp(&a.created_at));
let default_deployment = all_deployments
.iter()
.find(|d| d.status == DeploymentStatus::SUCCESS)
.or_else(|| all_deployments.first())
.context("No deployments found")?;
let default_deployment = if args.latest {
all_deployments.first()
} else {
all_deployments
.iter()
.find(|d| d.status == DeploymentStatus::SUCCESS)
.or_else(|| all_deployments.first())
}
.context("No deployments found")?;
let deployment_id = if let Some(deployment_id) = args.deployment_id {
// Use the provided deployment ID directly

View file

@ -28,6 +28,12 @@ query Project($id: String!) {
createdAt
deploymentStopped
}
activeDeployments {
id
status
createdAt
meta
}
source {
repo
image

823
src/gql/schema.json generated
View file

@ -160,12 +160,6 @@
"isDeprecated": false,
"name": "CONVERSATIONAL_UI"
},
{
"deprecationReason": null,
"description": null,
"isDeprecated": false,
"name": "HTTP_SERVICE_METRICS"
},
{
"deprecationReason": null,
"description": null,
@ -176,7 +170,7 @@
"deprecationReason": null,
"description": null,
"isDeprecated": false,
"name": "MONOREPO_SUPPORT"
"name": "POSTGRES_HA"
},
{
"deprecationReason": null,
@ -253,13 +247,13 @@
"deprecationReason": null,
"description": null,
"isDeprecated": false,
"name": "MONOREPO_SUPPORT"
"name": "SCYLLADB_ROUTING_ENABLED"
},
{
"deprecationReason": null,
"description": null,
"isDeprecated": false,
"name": "SCYLLADB_ROUTING_ENABLED"
"name": "SERVICEINSTANCE_DATALOADER_FOR_STATIC_URL"
},
{
"deprecationReason": null,
@ -302,6 +296,18 @@
"isDeprecated": false,
"name": "COPY_VOLUME_TO_ENVIRONMENT"
},
{
"deprecationReason": null,
"description": null,
"isDeprecated": false,
"name": "ENABLE_DOCKER_EXTENSION"
},
{
"deprecationReason": null,
"description": null,
"isDeprecated": false,
"name": "ENABLE_ONLINE_VOLUME_RESIZING"
},
{
"deprecationReason": null,
"description": null,
@ -1153,6 +1159,267 @@
"name": "AppliedByMember",
"possibleTypes": null
},
{
"description": null,
"enumValues": null,
"fields": [
{
"args": [],
"deprecationReason": null,
"description": null,
"isDeprecated": false,
"name": "context",
"type": {
"kind": "SCALAR",
"name": "JSON",
"ofType": null
}
},
{
"args": [],
"deprecationReason": null,
"description": null,
"isDeprecated": false,
"name": "createdAt",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "DateTime",
"ofType": null
}
}
},
{
"args": [],
"deprecationReason": null,
"description": null,
"isDeprecated": false,
"name": "environment",
"type": {
"kind": "OBJECT",
"name": "Environment",
"ofType": null
}
},
{
"args": [],
"deprecationReason": null,
"description": null,
"isDeprecated": false,
"name": "environmentId",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
{
"args": [],
"deprecationReason": null,
"description": null,
"isDeprecated": false,
"name": "eventType",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
}
},
{
"args": [],
"deprecationReason": null,
"description": null,
"isDeprecated": false,
"name": "id",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "ID",
"ofType": null
}
}
},
{
"args": [],
"deprecationReason": null,
"description": null,
"isDeprecated": false,
"name": "payload",
"type": {
"kind": "SCALAR",
"name": "JSON",
"ofType": null
}
},
{
"args": [],
"deprecationReason": null,
"description": null,
"isDeprecated": false,
"name": "project",
"type": {
"kind": "OBJECT",
"name": "Project",
"ofType": null
}
},
{
"args": [],
"deprecationReason": null,
"description": null,
"isDeprecated": false,
"name": "projectId",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
{
"args": [],
"deprecationReason": null,
"description": null,
"isDeprecated": false,
"name": "workspaceId",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
}
],
"inputFields": null,
"interfaces": [
{
"kind": "INTERFACE",
"name": "Node",
"ofType": null
}
],
"kind": "OBJECT",
"name": "AuditLog",
"possibleTypes": null
},
{
"description": null,
"enumValues": null,
"fields": [
{
"args": [],
"deprecationReason": null,
"description": null,
"isDeprecated": false,
"name": "description",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
}
},
{
"args": [],
"deprecationReason": null,
"description": null,
"isDeprecated": false,
"name": "eventType",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
}
}
],
"inputFields": null,
"interfaces": [],
"kind": "OBJECT",
"name": "AuditLogEventTypeInfo",
"possibleTypes": null
},
{
"description": null,
"enumValues": null,
"fields": null,
"inputFields": [
{
"defaultValue": null,
"description": "Filter events created on or before this date",
"name": "endDate",
"type": {
"kind": "SCALAR",
"name": "DateTime",
"ofType": null
}
},
{
"defaultValue": null,
"description": "Filter events for a single environment",
"name": "environmentId",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
{
"defaultValue": null,
"description": "List of event types to filter by",
"name": "eventTypes",
"type": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
}
}
},
{
"defaultValue": null,
"description": "Filter events for a single project",
"name": "projectId",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
{
"defaultValue": null,
"description": "Filter events created on or after this date",
"name": "startDate",
"type": {
"kind": "SCALAR",
"name": "DateTime",
"ofType": null
}
}
],
"interfaces": null,
"kind": "INPUT_OBJECT",
"name": "AuditLogFilterInput",
"possibleTypes": null
},
{
"description": null,
"enumValues": null,
@ -15563,6 +15830,16 @@
},
{
"args": [
{
"defaultValue": null,
"description": "Optional name/label for the backup. Defaults to 'Manual' if not provided.",
"name": "name",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
{
"defaultValue": null,
"description": "The id of the volume instance to create a backup of",
@ -16258,6 +16535,11 @@
"name": "ApiToken",
"ofType": null
},
{
"kind": "OBJECT",
"name": "AuditLog",
"ofType": null
},
{
"kind": "OBJECT",
"name": "Container",
@ -18658,13 +18940,13 @@
"deprecationReason": null,
"description": null,
"isDeprecated": false,
"name": "MONOREPO_SUPPORT"
"name": "SCYLLADB_ROUTING_ENABLED"
},
{
"deprecationReason": null,
"description": null,
"isDeprecated": false,
"name": "SCYLLADB_ROUTING_ENABLED"
"name": "SERVICEINSTANCE_DATALOADER_FOR_STATIC_URL"
},
{
"deprecationReason": null,
@ -23945,6 +24227,166 @@
}
}
},
{
"args": [
{
"defaultValue": null,
"description": "The ID of the audit log entry",
"name": "id",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
}
},
{
"defaultValue": null,
"description": "The ID of the workspace",
"name": "workspaceId",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
}
}
],
"deprecationReason": null,
"description": "Get an audit log by ID",
"isDeprecated": false,
"name": "auditLog",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "OBJECT",
"name": "AuditLog",
"ofType": null
}
}
},
{
"args": [],
"deprecationReason": null,
"description": "Get a list of all audit log event types and their description",
"isDeprecated": false,
"name": "auditLogEventTypeInfo",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "OBJECT",
"name": "AuditLogEventTypeInfo",
"ofType": null
}
}
}
}
},
{
"args": [
{
"defaultValue": null,
"description": null,
"name": "after",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
{
"defaultValue": null,
"description": null,
"name": "before",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
{
"defaultValue": null,
"description": null,
"name": "filter",
"type": {
"kind": "INPUT_OBJECT",
"name": "AuditLogFilterInput",
"ofType": null
}
},
{
"defaultValue": null,
"description": null,
"name": "first",
"type": {
"kind": "SCALAR",
"name": "Int",
"ofType": null
}
},
{
"defaultValue": null,
"description": null,
"name": "last",
"type": {
"kind": "SCALAR",
"name": "Int",
"ofType": null
}
},
{
"defaultValue": null,
"description": null,
"name": "sort",
"type": {
"kind": "ENUM",
"name": "SortOrder",
"ofType": null
}
},
{
"defaultValue": null,
"description": null,
"name": "workspaceId",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
}
}
],
"deprecationReason": null,
"description": "Gets audit logs for a workspace.",
"isDeprecated": false,
"name": "auditLogs",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "OBJECT",
"name": "QueryAuditLogsConnection",
"ofType": null
}
}
},
{
"args": [
{
@ -27713,6 +28155,37 @@
}
}
},
{
"args": [
{
"defaultValue": null,
"description": null,
"name": "id",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
}
}
],
"deprecationReason": null,
"description": "Get the metrics for a template.",
"isDeprecated": false,
"name": "templateMetrics",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "OBJECT",
"name": "TemplateMetrics",
"ofType": null
}
}
},
{
"args": [
{
@ -28739,6 +29212,100 @@
"name": "QueryApiTokensConnectionEdge",
"possibleTypes": null
},
{
"description": null,
"enumValues": null,
"fields": [
{
"args": [],
"deprecationReason": null,
"description": null,
"isDeprecated": false,
"name": "edges",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "OBJECT",
"name": "QueryAuditLogsConnectionEdge",
"ofType": null
}
}
}
}
},
{
"args": [],
"deprecationReason": null,
"description": null,
"isDeprecated": false,
"name": "pageInfo",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "OBJECT",
"name": "PageInfo",
"ofType": null
}
}
}
],
"inputFields": null,
"interfaces": [],
"kind": "OBJECT",
"name": "QueryAuditLogsConnection",
"possibleTypes": null
},
{
"description": null,
"enumValues": null,
"fields": [
{
"args": [],
"deprecationReason": null,
"description": null,
"isDeprecated": false,
"name": "cursor",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
}
},
{
"args": [],
"deprecationReason": null,
"description": null,
"isDeprecated": false,
"name": "node",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "OBJECT",
"name": "AuditLog",
"ofType": null
}
}
}
],
"inputFields": null,
"interfaces": [],
"kind": "OBJECT",
"name": "QueryAuditLogsConnectionEdge",
"possibleTypes": null
},
{
"description": null,
"enumValues": null,
@ -32557,6 +33124,30 @@
"description": null,
"enumValues": null,
"fields": [
{
"args": [],
"deprecationReason": null,
"description": "All currently active (deployed and running) deployments for this service instance",
"isDeprecated": false,
"name": "activeDeployments",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "OBJECT",
"name": "Deployment",
"ofType": null
}
}
}
}
},
{
"args": [],
"deprecationReason": null,
@ -32740,7 +33331,7 @@
{
"args": [],
"deprecationReason": null,
"description": null,
"description": "The most recent deployment for this service instance",
"isDeprecated": false,
"name": "latestDeployment",
"type": {
@ -34037,6 +34628,29 @@
"name": "SimilarTemplate",
"possibleTypes": null
},
{
"description": null,
"enumValues": [
{
"deprecationReason": null,
"description": null,
"isDeprecated": false,
"name": "asc"
},
{
"deprecationReason": null,
"description": null,
"isDeprecated": false,
"name": "desc"
}
],
"fields": null,
"inputFields": null,
"interfaces": null,
"kind": "ENUM",
"name": "SortOrder",
"possibleTypes": null
},
{
"description": "The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.",
"enumValues": null,
@ -34637,6 +35251,22 @@
"ofType": null
}
}
},
{
"args": [],
"deprecationReason": null,
"description": null,
"isDeprecated": false,
"name": "couponName",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
}
}
],
"inputFields": null,
@ -34665,6 +35295,18 @@
}
}
},
{
"args": [],
"deprecationReason": null,
"description": null,
"isDeprecated": false,
"name": "priceDollars",
"type": {
"kind": "SCALAR",
"name": "Float",
"ofType": null
}
},
{
"args": [],
"deprecationReason": null,
@ -34832,7 +35474,7 @@
"possibleTypes": null
},
{
"description": null,
"description": "\nSupport Health Metrics for Template Support Bonus Calculation..\nContains metrics calculated from community support thread performance:\n- solved: Percentage (0-100) of solved threads\n- csat: Percentage (0-100) of threads with positive customer satisfaction\n- aggregateHealth: Average of solved and csat when both available, otherwise just solved percentage\nTemplates with aggregateHealth >= 80 qualify for support bonus (additional 10% kickback).\n",
"enumValues": null,
"fields": null,
"inputFields": null,
@ -36836,6 +37478,161 @@
"name": "TemplateMetadata",
"possibleTypes": null
},
{
"description": null,
"enumValues": null,
"fields": [
{
"args": [],
"deprecationReason": null,
"description": null,
"isDeprecated": false,
"name": "activeDeployments",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "Int",
"ofType": null
}
}
},
{
"args": [],
"deprecationReason": null,
"description": null,
"isDeprecated": false,
"name": "deploymentsLast90Days",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "Int",
"ofType": null
}
}
},
{
"args": [],
"deprecationReason": null,
"description": null,
"isDeprecated": false,
"name": "earningsLast30Days",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "Float",
"ofType": null
}
}
},
{
"args": [],
"deprecationReason": null,
"description": null,
"isDeprecated": false,
"name": "earningsLast90Days",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "Float",
"ofType": null
}
}
},
{
"args": [],
"deprecationReason": null,
"description": null,
"isDeprecated": false,
"name": "eligibleForSupportBonus",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "Boolean",
"ofType": null
}
}
},
{
"args": [],
"deprecationReason": null,
"description": null,
"isDeprecated": false,
"name": "supportHealth",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "Float",
"ofType": null
}
}
},
{
"args": [],
"deprecationReason": null,
"description": null,
"isDeprecated": false,
"name": "templateHealth",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "Float",
"ofType": null
}
}
},
{
"args": [],
"deprecationReason": null,
"description": null,
"isDeprecated": false,
"name": "totalDeployments",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "Int",
"ofType": null
}
}
},
{
"args": [],
"deprecationReason": null,
"description": null,
"isDeprecated": false,
"name": "totalEarnings",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "Float",
"ofType": null
}
}
}
],
"inputFields": null,
"interfaces": [],
"kind": "OBJECT",
"name": "TemplateMetrics",
"possibleTypes": null
},
{
"description": null,
"enumValues": null,