Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 51 additions & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,14 @@ jobs:
else
echo "has_rust=false" >> $GITHUB_OUTPUT
fi
# A rust *backend* (python extension built via maturin) is identified by a
# pyproject.toml alongside the crate; a plain rust crate (e.g. generated
# protocol types) has none and is exercised by cargo only.
if ls ${{ matrix.package }}/crates/*/pyproject.toml 1>/dev/null 2>&1; then
echo "has_rust_backend=true" >> $GITHUB_OUTPUT
else
echo "has_rust_backend=false" >> $GITHUB_OUTPUT
fi

- name: Set up Python ${{ matrix.version }}
uses: actions/setup-python@v6
Expand Down Expand Up @@ -186,7 +194,7 @@ jobs:
DISABLE_SENTRY: True

- name: Run Rust backend tests
if: steps.detect.outputs.has_rust == 'true'
if: steps.detect.outputs.has_rust_backend == 'true'
run: |
cd ${{ matrix.package }}
pytest tests --backend=rust -v
Expand Down Expand Up @@ -536,6 +544,47 @@ jobs:
npm publish --access public
fi

publish-crate:
name: Publish ${{ matrix.crate.name }} to crates.io
needs: [ build, tests ]
if: github.event_name == 'push' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/dev')
runs-on: ubuntu-latest
strategy:
fail-fast: false # one crate failing must not cancel the others
matrix:
crate:
- { name: octobot-protocol, dir: packages/protocol/crates/octobot_protocol_rs }
# add future crates here: - { name: <crate>, dir: <path> }
permissions:
contents: read
id-token: write # required for crates.io trusted publishing (OIDC, no token needed)
defaults:
run:
working-directory: ${{ matrix.crate.dir }}

steps:
- uses: actions/checkout@v6

- uses: dtolnay/rust-toolchain@stable

- name: Authenticate to crates.io (OIDC trusted publishing)
uses: rust-lang/crates-io-auth-action@v1
id: auth

- name: Publish ${{ matrix.crate.name }} if version not already on crates.io
env:
CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }}
run: |
NAME='${{ matrix.crate.name }}'
VERSION=$(cargo metadata --no-deps --format-version 1 | python3 -c "import sys,json;print(next(p['version'] for p in json.load(sys.stdin)['packages'] if p['name']=='$NAME'))")
if curl -sf -H "User-Agent: octobot-ci (paul@drakkar.software)" \
"https://crates.io/api/v1/crates/$NAME/$VERSION" >/dev/null 2>&1; then
echo "$NAME@$VERSION is already published — nothing to do."
else
echo "Publishing $NAME@$VERSION..."
cargo publish -p "$NAME"
fi

version:
needs: [ build, tests ]
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags')
Expand Down Expand Up @@ -790,6 +839,7 @@ jobs:
- version
- docs
- publish-npm
- publish-crate
uses: Drakkar-Software/.github/.github/workflows/failure_notify_workflow.yml@master
secrets:
DISCORD_GITHUB_WEBHOOK: ${{ secrets.DISCORD_GITHUB_WEBHOOK }}
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,10 @@ docs/static/llms.txt
# PyBuilder
target/

# Rust workspace lockfile — resolved fresh in CI, mirroring the no-committed-lockfile
# convention used for the other protocol flavors
Cargo.lock

# Jupyter Notebook
.ipynb_checkpoints

Expand Down
1 change: 0 additions & 1 deletion packages/protocol/.gitignore

This file was deleted.

16 changes: 16 additions & 0 deletions packages/protocol/crates/octobot_protocol_rs/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[package]
name = "octobot-protocol"
version = "0.3.0"
edition = "2021"
license = "GPL-3.0"
description = "Rust types generated from the OctoBot OpenAPI schema"
repository = "https://github.com/Drakkar-Software/OctoBot"
readme = "README.md"

[lib]
name = "octobot_protocol"

[dependencies]
serde = { version = "1", features = ["derive"] }
serde_json = "1"
chrono = { version = "0.4", features = ["serde"] }
15 changes: 15 additions & 0 deletions packages/protocol/crates/octobot_protocol_rs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# octobot-protocol

Rust types generated from the [OctoBot](https://github.com/Drakkar-Software/OctoBot) OpenAPI
schema (`packages/protocol/openapi.json`).

The crate exposes serde-(de)serializable model types under `octobot_protocol::models`. It is
generated by `openapi-generator` and regenerated from the schema — do not edit the contents of
`src/models/` by hand. Run `npm run generate:rust` in `packages/protocol/` to regenerate.

```rust
use octobot_protocol::models::WorkflowStatus;
```

Published under the same `0.x` version as the TypeScript (`@drakkar.software/octobot-protocol`)
and Python (`octobot_protocol`) flavors generated from the same schema.
4 changes: 4 additions & 0 deletions packages/protocol/crates/octobot_protocol_rs/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#![allow(unused_imports)]
#![allow(clippy::all)]

pub mod models;
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* OctoBot protocol types
*
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* The version of the OpenAPI document: 1.0.0
*
* Generated by: https://openapi-generator.tech
*/

use crate::models;
use serde::{Deserialize, Serialize};

/// Account : Account
#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
pub struct Account {
#[serde(rename = "id")]
pub id: String,
#[serde(rename = "name")]
pub name: String,
#[serde(rename = "is_simulated")]
pub is_simulated: bool,
#[serde(rename = "description", skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(rename = "state", skip_serializing_if = "Option::is_none")]
pub state: Option<Box<models::AccountState>>,
#[serde(rename = "created_at")]
pub created_at: chrono::DateTime<chrono::FixedOffset>,
#[serde(rename = "updated_at", skip_serializing_if = "Option::is_none")]
pub updated_at: Option<chrono::DateTime<chrono::FixedOffset>>,
/// The id of the account authentication bound to this account
#[serde(rename = "authentication_id", skip_serializing_if = "Option::is_none")]
pub authentication_id: Option<String>,
#[serde(rename = "assets", skip_serializing_if = "Option::is_none")]
pub assets: Option<Vec<models::DetailedAssetsForTradingType>>,
#[serde(rename = "specifics", skip_serializing_if = "Option::is_none")]
pub specifics: Option<Box<models::AccountSpecifics>>,
}

impl Account {
/// Account
pub fn new(id: String, name: String, is_simulated: bool, created_at: chrono::DateTime<chrono::FixedOffset>) -> Account {
Account {
id,
name,
is_simulated,
description: None,
state: None,
created_at,
updated_at: None,
authentication_id: None,
assets: None,
specifics: None,
}
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* OctoBot protocol types
*
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* The version of the OpenAPI document: 1.0.0
*
* Generated by: https://openapi-generator.tech
*/

use crate::models;
use serde::{Deserialize, Serialize};

/// AccountActionResult : AccountActionResult
#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
pub struct AccountActionResult {
#[serde(rename = "updated_at")]
pub updated_at: chrono::DateTime<chrono::FixedOffset>,
#[serde(rename = "error_message", skip_serializing_if = "Option::is_none")]
pub error_message: Option<models::AccountActionResultErrorMessage>,
#[serde(rename = "error_details", skip_serializing_if = "Option::is_none")]
pub error_details: Option<String>,
#[serde(rename = "result_type")]
pub result_type: models::UserActionResultType,
}

impl AccountActionResult {
/// AccountActionResult
pub fn new(updated_at: chrono::DateTime<chrono::FixedOffset>, result_type: models::UserActionResultType) -> AccountActionResult {
AccountActionResult {
updated_at,
error_message: None,
error_details: None,
result_type,
}
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* OctoBot protocol types
*
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* The version of the OpenAPI document: 1.0.0
*
* Generated by: https://openapi-generator.tech
*/

use crate::models;
use serde::{Deserialize, Serialize};

/// AccountActionResultErrorMessage : AccountActionResultErrorMessage
/// AccountActionResultErrorMessage
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
pub enum AccountActionResultErrorMessage {
#[serde(rename = "account_not_found")]
AccountNotFound,
#[serde(rename = "invalid_configuration")]
InvalidConfiguration,
#[serde(rename = "duplicate_item")]
DuplicateItem,
#[serde(rename = "account_authentication_details_not_found")]
AccountAuthenticationDetailsNotFound,
#[serde(rename = "internal_error")]
InternalError,

}

impl std::fmt::Display for AccountActionResultErrorMessage {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
Self::AccountNotFound => write!(f, "account_not_found"),
Self::InvalidConfiguration => write!(f, "invalid_configuration"),
Self::DuplicateItem => write!(f, "duplicate_item"),
Self::AccountAuthenticationDetailsNotFound => write!(f, "account_authentication_details_not_found"),
Self::InternalError => write!(f, "internal_error"),
}
}
}

impl Default for AccountActionResultErrorMessage {
fn default() -> AccountActionResultErrorMessage {
Self::AccountNotFound
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* OctoBot protocol types
*
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* The version of the OpenAPI document: 1.0.0
*
* Generated by: https://openapi-generator.tech
*/

use crate::models;
use serde::{Deserialize, Serialize};

/// AccountAuthActionResult : AccountAuthActionResult
#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
pub struct AccountAuthActionResult {
#[serde(rename = "updated_at")]
pub updated_at: chrono::DateTime<chrono::FixedOffset>,
#[serde(rename = "error_message", skip_serializing_if = "Option::is_none")]
pub error_message: Option<models::AccountAuthActionResultErrorMessage>,
#[serde(rename = "error_details", skip_serializing_if = "Option::is_none")]
pub error_details: Option<String>,
/// account_auth
#[serde(rename = "result_type")]
pub result_type: models::UserActionResultType,
}

impl AccountAuthActionResult {
/// AccountAuthActionResult
pub fn new(updated_at: chrono::DateTime<chrono::FixedOffset>, result_type: models::UserActionResultType) -> AccountAuthActionResult {
AccountAuthActionResult {
updated_at,
error_message: None,
error_details: None,
result_type,
}
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* OctoBot protocol types
*
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* The version of the OpenAPI document: 1.0.0
*
* Generated by: https://openapi-generator.tech
*/

use crate::models;
use serde::{Deserialize, Serialize};

/// AccountAuthActionResultErrorMessage : AccountAuthActionResultErrorMessage
/// AccountAuthActionResultErrorMessage
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
pub enum AccountAuthActionResultErrorMessage {
#[serde(rename = "account_auth_not_found")]
AccountAuthNotFound,
#[serde(rename = "invalid_configuration")]
InvalidConfiguration,
#[serde(rename = "duplicate_item")]
DuplicateItem,
#[serde(rename = "internal_error")]
InternalError,

}

impl std::fmt::Display for AccountAuthActionResultErrorMessage {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
Self::AccountAuthNotFound => write!(f, "account_auth_not_found"),
Self::InvalidConfiguration => write!(f, "invalid_configuration"),
Self::DuplicateItem => write!(f, "duplicate_item"),
Self::InternalError => write!(f, "internal_error"),
}
}
}

impl Default for AccountAuthActionResultErrorMessage {
fn default() -> AccountAuthActionResultErrorMessage {
Self::AccountAuthNotFound
}
}

Loading
Loading