diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 653bc07..0cffe12 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -5,18 +5,30 @@ on: workflow_call: jobs: - build-artifacts-ARM64-macOS: - runs-on: macos-latest-xlarge + build-artifacts: + runs-on: ${{ matrix.systems.runner }} + strategy: + matrix: + systems: + - nix-system: x86_64-linux + system: X64-Linux + runner: ubuntu-22.04 + - nix-system: aarch64-linux + system: ARM64-Linux + runner: namespace-profile-default-arm64 + - nix-system: x86_64-darwin + system: X64-macOS + runner: macos-12 + - nix-system: aarch64-darwin + system: ARM64-macOS + runner: macos-latest-xlarge permissions: contents: read id-token: write steps: - uses: actions/checkout@v3 - - uses: DeterminateSystems/nix-installer-action@main - - uses: DeterminateSystems/magic-nix-cache-action@main - - name: Build package run: "nix build .# -L --fallback && nix-store --export $(nix-store -qR ./result) | xz -9 > magic-nix-cache.closure.xz" @@ -24,81 +36,6 @@ jobs: uses: actions/upload-artifact@v3.1.2 with: # Artifact name - name: magic-nix-cache-ARM64-macOS - path: magic-nix-cache.closure.xz - retention-days: 1 - - build-artifacts-X64-macOS: - runs-on: macos-12 - permissions: - contents: read - id-token: write - steps: - - uses: actions/checkout@v3 - - - uses: DeterminateSystems/flake-checker-action@main - - - uses: DeterminateSystems/nix-installer-action@main - - - uses: DeterminateSystems/magic-nix-cache-action@main - - - name: Build package - run: "nix build .# -L --fallback && nix-store --export $(nix-store -qR ./result) | xz -9 > magic-nix-cache.closure.xz" - - - name: Upload a Build Artifact - uses: actions/upload-artifact@v3.1.2 - with: - # Artifact name - name: magic-nix-cache-X64-macOS - path: magic-nix-cache.closure.xz - retention-days: 1 - - build-artifacts-X64-Linux: - runs-on: ubuntu-22.04 - permissions: - contents: read - id-token: write - steps: - - uses: actions/checkout@v3 - - - uses: DeterminateSystems/flake-checker-action@main - - - uses: DeterminateSystems/nix-installer-action@main - - - uses: DeterminateSystems/magic-nix-cache-action@main - - - name: Build package - run: "nix build .# -L --fallback && nix-store --export $(nix-store -qR ./result) | xz -9 > magic-nix-cache.closure.xz" - - - name: Upload a Build Artifact - uses: actions/upload-artifact@v3.1.2 - with: - # Artifact name - name: magic-nix-cache-X64-Linux - path: magic-nix-cache.closure.xz - retention-days: 1 - - build-artifacts-ARM64-Linux: - runs-on: namespace-profile-default-arm64 - permissions: - contents: read - id-token: write - steps: - - uses: actions/checkout@v3 - - - uses: DeterminateSystems/flake-checker-action@main - - - uses: DeterminateSystems/nix-installer-action@main - - - uses: DeterminateSystems/magic-nix-cache-action@main - - - name: Build package - run: "nix build .# -L --fallback && nix-store --export $(nix-store -qR ./result) | xz -9 > magic-nix-cache.closure.xz" - - - name: Upload a Build Artifact - uses: actions/upload-artifact@v3.1.2 - with: - # Artifact name - name: magic-nix-cache-ARM64-Linux + name: magic-nix-cache-${{ matrix.systems.system }} path: magic-nix-cache.closure.xz retention-days: 1 diff --git a/flake.nix b/flake.nix index d15722f..697c2a7 100644 --- a/flake.nix +++ b/flake.nix @@ -55,7 +55,7 @@ cargo-bloat cargo-edit cargo-udeps - cargo-watch + bacon age ]; diff --git a/magic-nix-cache/src/env.rs b/magic-nix-cache/src/env.rs new file mode 100644 index 0000000..1b59405 --- /dev/null +++ b/magic-nix-cache/src/env.rs @@ -0,0 +1,50 @@ +use std::fmt::{self, Display}; + +#[derive(Clone, Copy)] +pub enum Environment { + GitHubActions, + GitLabCI, + Other, +} + +impl Environment { + pub fn determine() -> Self { + if env_var_is_true("GITHUB_ACTIONS") { + return Environment::GitHubActions; + } + + if env_var_is_true("GITLAB_CI") { + return Environment::GitLabCI; + } + + Environment::Other + } + + pub fn is_github_actions(&self) -> bool { + matches!(self, Self::GitHubActions) + } + + pub fn is_gitlab_ci(&self) -> bool { + matches!(self, Self::GitLabCI) + } +} + +impl Display for Environment { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use Environment::*; + + write!( + f, + "{}", + match self { + GitHubActions => "GitHub Actions", + GitLabCI => "GitLab CI", + Other => "an unspecified environment", + } + ) + } +} + +fn env_var_is_true(e: &str) -> bool { + std::env::var(e).is_ok_and(|v| v == "true") +} diff --git a/magic-nix-cache/src/flakehub.rs b/magic-nix-cache/src/flakehub.rs index 1dbd79a..b3d3a6f 100644 --- a/magic-nix-cache/src/flakehub.rs +++ b/magic-nix-cache/src/flakehub.rs @@ -1,3 +1,4 @@ +use crate::env::Environment; use crate::error::{Error, Result}; use attic::cache::CacheName; use attic::nix_store::{NixStore, StorePath}; @@ -27,6 +28,7 @@ pub struct State { } pub async fn init_cache( + environment: Environment, flakehub_api_server: &Url, flakehub_api_server_netrc: &Path, flakehub_cache_server: &Url, @@ -102,22 +104,26 @@ pub async fn init_cache( let api_inner = ApiClient::from_server_config(server_config)?; let api = Arc::new(RwLock::new(api_inner)); - // NOTE(cole-h): This is a workaround -- at the time of writing, GitHub Actions JWTs are only - // valid for 5 minutes after being issued. FlakeHub uses these JWTs for authentication, which - // means that after those 5 minutes have passed and the token is expired, FlakeHub (and by - // extension FlakeHub Cache) will no longer allow requests using this token. However, GitHub - // gives us a way to repeatedly request new tokens, so we utilize that and refresh the token - // every 2 minutes (less than half of the lifetime of the token). - let netrc_path_clone = flakehub_api_server_netrc.to_path_buf(); - let initial_github_jwt_clone = flakehub_password.clone(); - let flakehub_cache_server_clone = flakehub_cache_server.to_string(); - let api_clone = api.clone(); - tokio::task::spawn(refresh_github_actions_jwt_worker( - netrc_path_clone, - initial_github_jwt_clone, - flakehub_cache_server_clone, - api_clone, - )); + // Periodically refresh JWT in GitHub Actions environment + if environment.is_github_actions() { + // NOTE(cole-h): This is a workaround -- at the time of writing, GitHub Actions JWTs are only + // valid for 5 minutes after being issued. FlakeHub uses these JWTs for authentication, which + // means that after those 5 minutes have passed and the token is expired, FlakeHub (and by + // extension FlakeHub Cache) will no longer allow requests using this token. However, GitHub + // gives us a way to repeatedly request new tokens, so we utilize that and refresh the token + // every 2 minutes (less than half of the lifetime of the token). + let netrc_path_clone = flakehub_api_server_netrc.to_path_buf(); + let initial_github_jwt_clone = flakehub_password.clone(); + let flakehub_cache_server_clone = flakehub_cache_server.to_string(); + let api_clone = api.clone(); + + tokio::task::spawn(refresh_github_actions_jwt_worker( + netrc_path_clone, + initial_github_jwt_clone, + flakehub_cache_server_clone, + api_clone, + )); + } // Get the cache UUID for this project. let cache_name = { diff --git a/magic-nix-cache/src/main.rs b/magic-nix-cache/src/main.rs index 4dabf22..f7f8d1e 100644 --- a/magic-nix-cache/src/main.rs +++ b/magic-nix-cache/src/main.rs @@ -14,6 +14,7 @@ mod api; mod binary_cache; +mod env; mod error; mod flakehub; mod gha; @@ -112,6 +113,24 @@ struct Args { startup_notification_url: Option, } +impl Args { + fn validate(&self, environment: env::Environment) -> Result<(), error::Error> { + if environment.is_gitlab_ci() && self.use_gha_cache { + return Err(error::Error::Config(String::from( + "the --use-gha-cache flag should not be applied in GitLab CI", + ))); + } + + if environment.is_gitlab_ci() && !self.use_flakehub { + return Err(error::Error::Config(String::from( + "you must set --use-flakehub in GitLab CI", + ))); + } + + Ok(()) + } +} + /// The global server state. struct StateInner { /// State for uploading to the GHA cache. @@ -140,6 +159,9 @@ async fn main_cli() -> Result<()> { init_logging(); let args = Args::parse(); + let environment = env::Environment::determine(); + tracing::debug!("Running in {}", environment.to_string()); + args.validate(environment)?; let metrics = Arc::new(telemetry::TelemetryReport::new()); @@ -167,6 +189,7 @@ async fn main_cli() -> Result<()> { let flakehub_flake_name = args.flakehub_flake_name; match flakehub::init_cache( + environment, &args .flakehub_api_server .ok_or_else(|| anyhow!("--flakehub-api-server is required"))?, @@ -240,7 +263,10 @@ async fn main_cli() -> Result<()> { tracing::info!("Native GitHub Action cache is enabled."); Some(gha_cache) } else { - tracing::info!("Native GitHub Action cache is disabled."); + if environment.is_github_actions() { + tracing::info!("Native GitHub Action cache is disabled."); + } + None };