ghactions_core/
lib.rs

1//! ghactions-core is a library that provides core functionality for GitHub Actions in Rust.
2#![allow(dead_code)]
3#![allow(unused_imports)]
4#![deny(missing_docs)]
5
6#[cfg(feature = "log")]
7extern crate log;
8
9use std::io::Write;
10use std::path::Path;
11
12pub mod actions;
13pub mod errors;
14// pub mod ghaction;
15#[cfg(feature = "log")]
16pub mod logging;
17pub mod repository;
18#[cfg(feature = "toolcache")]
19pub mod toolcache;
20
21pub use crate::actions::models::{ActionInput, ActionRuns, ActionYML};
22pub use crate::errors::ActionsError;
23pub use crate::repository::reference::RepositoryReference;
24
25/// Action Trait
26pub trait ActionTrait {
27    /// Parse the action input
28    fn init() -> Result<Self, ActionsError>
29    where
30        Self: Sized;
31
32    /// Get the action name
33    fn name(&self) -> &str;
34
35    /// Get the action description
36    fn description(&self) -> &str;
37
38    /// Get the input value for a provided key
39    fn get_input(key: impl Into<String> + Copy) -> Result<String, ActionsError> {
40        std::env::var(&key.into()).map_err(|_| ActionsError::InputError(key.into()))
41    }
42
43    /// Get the input value for a provided key as a boolean
44    fn get_input_bool(key: impl Into<String> + Copy) -> Result<bool, ActionsError> {
45        Self::get_input(key)?
46            .parse::<bool>()
47            .map_err(|_| ActionsError::InputTypeError(key.into(), "bool".into()))
48    }
49
50    /// Get the input value for a provided key as an integer
51    fn get_input_int(key: impl Into<String> + Copy) -> Result<i32, ActionsError> {
52        Self::get_input(key)?
53            .parse::<i32>()
54            .map_err(|_| ActionsError::InputTypeError(key.into(), "int".into()))
55    }
56
57    /// Get the input value for a provided key as a vector using a seperator
58    fn get_input_vec(
59        key: impl Into<String> + Copy,
60        seperator: &str,
61    ) -> Result<Vec<String>, ActionsError> {
62        Ok(Self::get_input(key)?
63            .split(seperator)
64            .map(|s| s.to_string())
65            .collect::<Vec<String>>())
66    }
67
68    /// Set the output value for a provided key
69    fn set_output(key: impl Into<String>, value: impl Into<String>) -> Result<(), ActionsError> {
70        let key = key.into();
71        let value = value.into();
72
73        let output = format!("::set-output name={}::{}", key, value);
74        let output_file = std::env::var("GITHUB_OUTPUT")
75            .unwrap_or_else(|_| "/tmp/github_actions.env".to_string());
76
77        #[cfg(feature = "log")]
78        {
79            log::debug!("{}", output);
80            log::debug!("Output File: {}", output_file);
81        }
82
83        let mut file = std::fs::OpenOptions::new()
84            .create(true)
85            .append(true)
86            .open(output_file)?;
87        writeln!(file, "{}", output)?;
88
89        Ok(())
90    }
91
92    /// Get the Octocrab instance
93    ///
94    /// Uses the `GITHUB_API_URL` and `GITHUB_TOKEN` environment variable to create an Octocrab instance
95    #[cfg(feature = "octocrab")]
96    fn octocrab(&self) -> Result<octocrab::Octocrab, ActionsError> {
97        #[cfg(feature = "log")]
98        {
99            log::debug!("Creating Octocrab instance");
100            log::debug!("URL: {}", self.get_api_url());
101        }
102
103        match self.get_token() {
104            Ok(token) => Ok(octocrab::Octocrab::builder()
105                .base_uri(self.get_api_url())
106                .map_err(|e| ActionsError::OctocrabError(e.to_string()))?
107                .add_header(
108                    http::header::ACCEPT,
109                    "application/vnd.github.v3+json".to_string(),
110                )
111                .personal_token(token)
112                .build()
113                .map_err(|e| ActionsError::OctocrabError(e.to_string()))?),
114            Err(_) => {
115                #[cfg(feature = "log")]
116                log::warn!("No GitHub Token provided");
117
118                Ok(octocrab::Octocrab::builder()
119                    .base_uri(self.get_api_url())
120                    .map_err(|e| ActionsError::OctocrabError(e.to_string()))?
121                    .add_header(
122                        http::header::ACCEPT,
123                        "application/vnd.github.v3+json".to_string(),
124                    )
125                    .build()
126                    .map_err(|e| ActionsError::OctocrabError(e.to_string()))?)
127            }
128        }
129    }
130
131    /// GetHub Server URL (default: https://github.com)
132    fn get_server_url(&self) -> String {
133        Self::get_input("GITHUB_SERVER_URL").unwrap_or_else(|_| "https://github.com".into())
134    }
135    /// GitHub API URL (default: https://api.github.com)
136    fn get_api_url(&self) -> String {
137        Self::get_input("GITHUB_API_URL").unwrap_or_else(|_| "https://api.github.com".into())
138    }
139    /// GitHub GraphQL URL (default: https://api.github.com/graphql)
140    fn get_graphql_url(&self) -> String {
141        Self::get_input("GITHUB_GRAPHQL_URL")
142            .unwrap_or_else(|_| "https://api.github.com/graphql".into())
143    }
144
145    /// Get the GitHub Token
146    fn get_token(&self) -> Result<String, ActionsError> {
147        Self::get_input("GITHUB_TOKEN")
148    }
149    /// Get the GitHub SHA
150    fn get_sha(&self) -> Result<String, ActionsError> {
151        Self::get_input("GITHUB_SHA")
152    }
153    /// Get the GitHub Ref (full)
154    fn get_ref(&self) -> Result<String, ActionsError> {
155        Self::get_input("GITHUB_REF")
156    }
157    /// Get the GitHub Ref Type
158    fn get_ref_type(&self) -> Result<String, ActionsError> {
159        Self::get_input("GITHUB_REF_TYPE")
160    }
161    /// Get the GitHub Ref Name
162    fn get_ref_name(&self) -> Result<String, ActionsError> {
163        Self::get_input("GITHUB_REF_NAME")
164    }
165
166    /// Get the GitHub Workflow Event Name
167    fn get_event_name(&self) -> Result<String, ActionsError> {
168        Self::get_input("GITHUB_EVENT_NAME")
169    }
170
171    /// Get the full GitHub Repository (owner/repo)
172    fn get_repository(&self) -> Result<String, ActionsError> {
173        Self::get_input("GITHUB_REPOSITORY")
174    }
175    /// Get the GitHub Repository owner name (org/user)
176    fn get_repository_owner(&self) -> Result<String, ActionsError> {
177        Self::get_input("GITHUB_REPOSITORY_OWNER").or_else(|_| {
178            self.get_repository()
179                .map(|r| r.split('/').collect::<Vec<&str>>()[0].to_string())
180        })
181    }
182    /// Get the GitHub Repository name
183    fn get_repository_name(&self) -> Result<String, ActionsError> {
184        self.get_repository()
185            .map(|r| r.split('/').collect::<Vec<&str>>()[1].to_string())
186    }
187    /// Get the GitHub Repository URL
188    fn get_repository_url(&self) -> Result<String, ActionsError> {
189        Self::get_input("GITHUB_REPOSITORYURL")
190    }
191    /// Get the Action Triggering Author
192    fn get_actor(&self) -> Result<String, ActionsError> {
193        Self::get_input("GITHUB_ACTOR")
194    }
195}