Repository: Azure/azure-sdk-for-rust (rust)

Issue:
Use `new` consistently for construction and factory methods
As a follow-up to #1532 we should use `new*` consistently for both "constructors" as well as factory methods instead of `create*`.

Pull request:
Remove azure_identity's from_env() constructors
Closes #1583 

Patch:
diff --git a/sdk/identity/azure_identity/CHANGELOG.md b/sdk/identity/azure_identity/CHANGELOG.md
index f430f4104..766ff4821 100644
--- a/sdk/identity/azure_identity/CHANGELOG.md
+++ b/sdk/identity/azure_identity/CHANGELOG.md
@@ -7,6 +7,7 @@
 ### Breaking Changes
 
 - Moved `WorkloadIdentityCredential::new` arguments into `WorkloadIdentityCredentialOptions` except `token`, which has been removed (the credential now reads service account tokens only from a file).
+- Removed `ClientAssertionCredential::from_env` and `ClientCertificateCredential::from_env`.
 - Removed `WorkloadIdentityCredential::from_env`. `::new` now reads the same environment variables except for `AZURE_FEDERATED_TOKEN` (the Workload Identity webhook doesn't set that variable). `WorkloadIdentityCredentialOptions` overrides environment variable values.
 
 ### Bugs Fixed
diff --git a/sdk/identity/azure_identity/src/credentials/client_assertion_credentials.rs b/sdk/identity/azure_identity/src/credentials/client_assertion_credentials.rs
index 312e00463..3a1734a3b 100644
--- a/sdk/identity/azure_identity/src/credentials/client_assertion_credentials.rs
+++ b/sdk/identity/azure_identity/src/credentials/client_assertion_credentials.rs
@@ -9,9 +9,6 @@ use azure_core::{
 use std::{fmt::Debug, str, sync::Arc, time::Duration};
 use time::OffsetDateTime;
 
-const AZURE_TENANT_ID_ENV_KEY: &str = "AZURE_TENANT_ID";
-const AZURE_CLIENT_ID_ENV_KEY: &str = "AZURE_CLIENT_ID";
-
 /// Enables authentication of a Microsoft Entra service principal using a signed client assertion.
 #[derive(Debug)]
 pub struct ClientAssertionCredential<C> {
@@ -80,53 +77,6 @@ impl<C: ClientAssertion> ClientAssertionCredential<C> {
         })
     }
 
-    /// Create a new `ClientAssertionCredential` from environment variables.
-    ///
-    /// # Variables
-    ///
-    /// * `AZURE_TENANT_ID`
-    /// * `AZURE_CLIENT_ID`
-    pub fn from_env(
-        assertion: C,
-        options: Option<ClientAssertionCredentialOptions>,
-    ) -> azure_core::Result<Arc<Self>> {
-        Ok(Arc::new(Self::from_env_exclusive(assertion, options)?))
-    }
-
-    /// Create a new `ClientAssertionCredential` from environment variables,
-    /// without wrapping it in an `Arc`. Intended for use by other credentials
-    /// in the crate that will themselves be protected by an `Arc`.
-    ///
-    /// # Variables
-    ///
-    /// * `AZURE_TENANT_ID`
-    /// * `AZURE_CLIENT_ID`
-    pub(crate) fn from_env_exclusive(
-        assertion: C,
-        options: Option<ClientAssertionCredentialOptions>,
-    ) -> azure_core::Result<Self> {
-        let options = options.unwrap_or_default();
-        let env = options.credential_options.env();
-        let tenant_id =
-            env.var(AZURE_TENANT_ID_ENV_KEY)
-                .with_context(ErrorKind::Credential, || {
-                    format!(
-                        "working identity credential requires {} environment variable",
-                        AZURE_TENANT_ID_ENV_KEY
-                    )
-                })?;
-        let client_id =
-            env.var(AZURE_CLIENT_ID_ENV_KEY)
-                .with_context(ErrorKind::Credential, || {
-                    format!(
-                        "working identity credential requires {} environment variable",
-                        AZURE_CLIENT_ID_ENV_KEY
-                    )
-                })?;
-
-        ClientAssertionCredential::new_exclusive(tenant_id, client_id, assertion, Some(options))
-    }
-
     async fn get_token(&self, scopes: &[&str]) -> azure_core::Result<AccessToken> {
         let token = self.assertion.secret().await?;
         let credential_options = &self.options.credential_options;
diff --git a/sdk/identity/azure_identity/src/credentials/client_certificate_credentials.rs b/sdk/identity/azure_identity/src/credentials/client_certificate_credentials.rs
index fb35ee1b4..ae2354cfd 100644
--- a/sdk/identity/azure_identity/src/credentials/client_certificate_credentials.rs
+++ b/sdk/identity/azure_identity/src/credentials/client_certificate_credentials.rs
@@ -5,7 +5,7 @@ use crate::{credentials::cache::TokenCache, EntraIdTokenResponse, TokenCredentia
 use azure_core::{
     base64,
     credentials::{AccessToken, Secret, TokenCredential},
-    error::{http_response_from_body, Error, ErrorKind, ResultExt},
+    error::{http_response_from_body, Error, ErrorKind},
     http::{
         headers::{self, content_type},
         request::Request,
@@ -30,10 +30,6 @@ use url::form_urlencoded;
 /// Refresh time to use in seconds.
 const DEFAULT_REFRESH_TIME: i64 = 300;
 
-const AZURE_TENANT_ID_ENV_KEY: &str = "AZURE_TENANT_ID";
-const AZURE_CLIENT_ID_ENV_KEY: &str = "AZURE_CLIENT_ID";
-const AZURE_CLIENT_CERTIFICATE_PATH_ENV_KEY: &str = "AZURE_CLIENT_CERTIFICATE_PATH";
-const AZURE_CLIENT_CERTIFICATE_PASSWORD_ENV_KEY: &str = "AZURE_CLIENT_CERTIFICATE_PASSWORD";
 const AZURE_CLIENT_SEND_CERTIFICATE_CHAIN_ENV_KEY: &str = "AZURE_CLIENT_SEND_CERTIFICATE_CHAIN";
 
 /// Provides options to configure how the Identity library makes authentication
@@ -264,69 +260,6 @@ impl ClientCertificateCredential {
             OffsetDateTime::now_utc() + Duration::from_secs(response.expires_in),
         ))
     }
-
-    /// Create a new `ClientCertificateCredential` from environment variables.
-    ///
-    /// # Variables
-    ///
-    /// * `AZURE_TENANT_ID`
-    /// * `AZURE_CLIENT_ID`
-    /// * `AZURE_CLIENT_CERTIFICATE_PATH`
-    /// * `AZURE_CLIENT_CERTIFICATE_PASSWORD`
-    pub fn from_env(
-        options: impl Into<ClientCertificateCredentialOptions>,
-    ) -> azure_core::Result<Arc<Self>> {
-        let options = options.into();
-        let env = options.options().env();
-        let tenant_id =
-            env.var(AZURE_TENANT_ID_ENV_KEY)
-                .with_context(ErrorKind::Credential, || {
-                    format!(
-                        "client certificate credential requires {} environment variable",
-                        AZURE_TENANT_ID_ENV_KEY
-                    )
-                })?;
-        let client_id =
-            env.var(AZURE_CLIENT_ID_ENV_KEY)
-                .with_context(ErrorKind::Credential, || {
-                    format!(
-                        "client certificate credential requires {} environment variable",
-                        AZURE_CLIENT_ID_ENV_KEY
-                    )
-                })?;
-        let client_certificate_path = env
-            .var(AZURE_CLIENT_CERTIFICATE_PATH_ENV_KEY)
-            .with_context(ErrorKind::Credential, || {
-                format!(
-                    "client certificate credential requires {} environment variable",
-                    AZURE_CLIENT_CERTIFICATE_PATH_ENV_KEY
-                )
-            })?;
-        let client_certificate_password = env
-            .var(AZURE_CLIENT_CERTIFICATE_PASSWORD_ENV_KEY)
-            .with_context(ErrorKind::Credential, || {
-                format!(
-                    "client certificate credential requires {} environment variable",
-                    AZURE_CLIENT_CERTIFICATE_PASSWORD_ENV_KEY
-                )
-            })?;
-
-        let client_certificate = std::fs::read_to_string(client_certificate_path.clone())
-            .with_context(ErrorKind::Credential, || {
-                format!(
-                    "failed to read client certificate from file {}",
-                    client_certificate_path.as_str()
-                )
-            })?;
-
-        ClientCertificateCredential::new(
-            tenant_id,
-            client_id,
-            client_certificate,
-            client_certificate_password,
-            options,
-        )
-    }
 }
 
 fn get_encoded_cert(cert: &X509) -> azure_core::Result<String> {
diff --git a/sdk/storage/assets.json b/sdk/storage/assets.json
index 320d3a2a8..343937af5 100644
--- a/sdk/storage/assets.json
+++ b/sdk/storage/assets.json
@@ -1,6 +1,6 @@
 {
   "AssetsRepo": "Azure/azure-sdk-assets",
   "AssetsRepoPrefixPath": "rust",
-  "Tag": "rust/azure_storage_blob_1a0956f648",
+  "Tag": "rust/azure_storage_blob_9f4842ba91",
   "TagPrefix": "rust/azure_storage_blob"
 }
\ No newline at end of file
diff --git a/sdk/storage/azure_storage_blob/src/clients/blob_client.rs b/sdk/storage/azure_storage_blob/src/clients/blob_client.rs
index 33318b7f4..b743e629c 100644
--- a/sdk/storage/azure_storage_blob/src/clients/blob_client.rs
+++ b/sdk/storage/azure_storage_blob/src/clients/blob_client.rs
@@ -8,12 +8,13 @@ use crate::{
         BlockBlobClientCommitBlockListResult, BlockBlobClientStageBlockResult,
         BlockBlobClientUploadResult,
     },
-    models::{BlockList, BlockListType, BlockLookupList},
+    models::{AccessTier, BlockList, BlockListType, BlockLookupList},
     pipeline::StorageHeadersPolicy,
     BlobClientDeleteOptions, BlobClientDownloadOptions, BlobClientGetPropertiesOptions,
     BlobClientOptions, BlobClientSetMetadataOptions, BlobClientSetPropertiesOptions,
-    BlockBlobClientCommitBlockListOptions, BlockBlobClientGetBlockListOptions,
-    BlockBlobClientStageBlockOptions, BlockBlobClientUploadOptions,
+    BlobClientSetTierOptions, BlockBlobClientCommitBlockListOptions,
+    BlockBlobClientGetBlockListOptions, BlockBlobClientStageBlockOptions,
+    BlockBlobClientUploadOptions,
 };
 use azure_core::{
     credentials::TokenCredential,
@@ -243,4 +244,19 @@ impl BlobClient {
         let response = block_blob_client.get_block_list(list_type, options).await?;
         Ok(response)
     }
+
+    /// Sets the tier on a blob. Standard tiers are only applicable for Block blobs, while Premium tiers are only applicable
+    /// for Page blobs.
+    ///
+    /// # Arguments
+    ///
+    /// * `tier` - The tier to be set on the blob.
+    /// * `options` - Optional configuration for the request.
+    pub async fn set_tier(
+        &self,
+        tier: AccessTier,
+        options: Option<BlobClientSetTierOptions<'_>>,
+    ) -> Result<Response<()>> {
+        self.client.set_tier(tier, options).await
+    }
 }
diff --git a/sdk/storage/azure_storage_blob/src/lib.rs b/sdk/storage/azure_storage_blob/src/lib.rs
index 2e722920c..75460580b 100644
--- a/sdk/storage/azure_storage_blob/src/lib.rs
+++ b/sdk/storage/azure_storage_blob/src/lib.rs
@@ -17,11 +17,12 @@ pub use crate::generated::clients::{
 };
 pub use crate::generated::models::{
     BlobClientDeleteOptions, BlobClientDownloadOptions, BlobClientGetPropertiesOptions,
-    BlobClientSetMetadataOptions, BlobClientSetPropertiesOptions, BlobContainerClientCreateOptions,
-    BlobContainerClientDeleteOptions, BlobContainerClientGetPropertiesOptions,
-    BlobContainerClientSetMetadataOptions, BlobServiceClientGetPropertiesOptions,
-    BlockBlobClientCommitBlockListOptions, BlockBlobClientGetBlockListOptions,
-    BlockBlobClientStageBlockOptions, BlockBlobClientUploadOptions,
+    BlobClientSetMetadataOptions, BlobClientSetPropertiesOptions, BlobClientSetTierOptions,
+    BlobContainerClientCreateOptions, BlobContainerClientDeleteOptions,
+    BlobContainerClientGetPropertiesOptions, BlobContainerClientSetMetadataOptions,
+    BlobServiceClientGetPropertiesOptions, BlockBlobClientCommitBlockListOptions,
+    BlockBlobClientGetBlockListOptions, BlockBlobClientStageBlockOptions,
+    BlockBlobClientUploadOptions,
 };
 
 pub mod models {


Test patch:
diff --git a/sdk/storage/azure_storage_blob/tests/blob_client.rs b/sdk/storage/azure_storage_blob/tests/blob_client.rs
index 0371c90ae..b56e59573 100644
--- a/sdk/storage/azure_storage_blob/tests/blob_client.rs
+++ b/sdk/storage/azure_storage_blob/tests/blob_client.rs
@@ -8,8 +8,8 @@ use azure_core::{
 use azure_core_test::{recorded, TestContext};
 use azure_storage_blob::{
     models::{
-        BlobClientDownloadResultHeaders, BlobClientGetPropertiesResultHeaders, BlockListType,
-        BlockLookupList, LeaseState,
+        AccessTier, BlobClientDownloadResultHeaders, BlobClientGetPropertiesResultHeaders,
+        BlockListType, BlockLookupList, LeaseState,
     },
     BlobClient, BlobClientOptions, BlobClientSetMetadataOptions, BlobClientSetPropertiesOptions,
     BlobContainerClient, BlobContainerClientOptions, BlockBlobClientUploadOptions,
@@ -670,3 +670,66 @@ async fn test_get_block_list(ctx: TestContext) -> Result<(), Box<dyn Error>> {
     container_client.delete_container(None).await?;
     Ok(())
 }
+
+#[recorded::test]
+async fn test_set_access_tier(ctx: TestContext) -> Result<(), Box<dyn Error>> {
+    // Recording Setup
+    let recording = ctx.recording();
+    let (options, endpoint) = recorded_test_setup(recording);
+    let container_name = recording
+        .random_string::<17>(Some("container"))
+        .to_ascii_lowercase();
+    let blob_name = recording
+        .random_string::<12>(Some("blob"))
+        .to_ascii_lowercase();
+
+    let container_client_options = BlobContainerClientOptions {
+        client_options: options.clone(),
+        ..Default::default()
+    };
+    // Act
+    let container_client = BlobContainerClient::new(
+        &endpoint,
+        container_name.clone(),
+        recording.credential(),
+        Some(container_client_options),
+    )?;
+
+    let blob_client_options = BlobClientOptions {
+        client_options: options.clone(),
+        ..Default::default()
+    };
+    let blob_client = BlobClient::new(
+        &endpoint,
+        container_name,
+        blob_name,
+        recording.credential(),
+        Some(blob_client_options),
+    )?;
+    container_client.create_container(None).await?;
+
+    let data = b"hello rusty world";
+    blob_client
+        .upload(
+            RequestContent::from(data.to_vec()),
+            true,
+            u64::try_from(data.len())?,
+            None,
+        )
+        .await?;
+
+    let original_response = blob_client.get_properties(None).await?;
+    let og_access_tier = original_response.tier()?;
+    assert_eq!(AccessTier::Hot, og_access_tier.unwrap());
+
+    // Set Standard Blob Tier (Cold)
+    blob_client.set_tier(AccessTier::Cold, None).await?;
+    let response = blob_client.get_properties(None).await?;
+
+    // Assert
+    let access_tier = response.tier()?;
+    assert_eq!(AccessTier::Cold, access_tier.unwrap());
+
+    container_client.delete_container(None).await?;
+    Ok(())
+}