2022年5月21日 星期六

Azure DevOps in Action - 部署到僅支援FTP的環境

除了採用Azure WebApp作為網站應用程式的運行環境之外,肯定有更多的開發人員,是採用其他的環境作網站的部署。有可能是主機代管,有可能是其他的雲端服務,也有可是地端環境。

那這些環境該如何進行部署呢? 最簡單的方式是透過FTP。

FTP是絕大部分網站肯定都支援的部署方式,也是傳統手動進行網站部署行為的時候,最常見的選擇。

要在Azure DevOps的pipeline當中進行FTP部署相當容易,你可以透過FTP Upload這個內建的task,即可完成上傳動作:
enter image description here
當你把該task加入job中之後,會看到底下設定:
enter image description here
上圖A的部分,是站台的身分驗證方式,你可以選擇為此站台建立一個connection或是直接輸入身帳號密碼,上圖中,我們選擇直接輸入帳密。

而上圖B、C、D三個欄位則是FTP伺服器的URL以及帳號密碼,這應沒什麽疑義。但需要注意的是上圖E,這個欄位需要輸入的是FTP來源檔案位置,也就是Pipeline當中,先前build好的artifacts所在的位置。這個位置從何而來? 由於目前我們展示的是CI Pipeline,因此該位置你應當參考前面Publish Task的結果:
enter image description here
參考上圖A,Buld好的結果預設的輸出位置使用了系統變數『$(build.artifactstagingdirectory)』,因此,我們在FTP Upload的Task中,Root Folder就是設定為『$(build.artifactstagingdirectory)』:
enter image description here
另外,請特別留意Publish Task中的『Zip published projects』選項,它預設是勾選的,你會發現我們將其取消了。原因是,勾選該項目,會讓publish task將發佈的成品壓縮成.zip檔案,但如此一來我們透過FTP送上站台的時候,反倒不能直接運行了。

因此,原本publish的zip選項必須取消。然後,我們再回頭看FTP Uploader task的Root foder,其設定就是先前Publish task的output位置:
enter image description here
最後,別忘了設定你上傳後這些檔案要放在遠端站台的哪一個路徑(上圖F),這個位置可能因為你選擇(或設定)的Web Server的不同而不同,上圖site/wwwroot是因為我們選用的是azure web app,其預設路徑就是site/wwwroot這個位置。

當你運行該Pipeline,會發現FTP Uploader確實可把檔案上傳到伺服器端:
enter image description here
如此一來,就可以順利地透過FTP在Pipeline中發佈網站囉。

備註:
上面的範例雖然是採用CI Pipeline來進行,但若讀者想要使用CD(Release) Pipeline來進行一樣的動作,當然也是可行的。

YT Video:
https://youtu.be/GgmwpaoJo84

參考資料:
Azure DevOps 顧問實戰
https://www.tenlong.com.tw/products/9786263241251?list_name=b-r7-zh_tw

電子書:
https://www.pubu.com.tw/ebook/288713

2022年5月16日 星期一

自動幫用戶開啟RichMenu與鍵盤or語音輸入

LINE在2022/5/13增加了postbackAction的屬性,讓發人員可以藉由送出一個含有postbackAction的訊息(類似底下這樣),來幫用戶來開啟(或關閉)rich menu,甚至可以開啟輸入鍵盤和語音:
enter image description here

上圖 A 的部分,是一個 Buttons Template Message,其中有四個按鈕,其類型都是我們先前介紹過的 postbackAction。

在過去,當用戶點下postbackAction按鈕時,只會讓伺服器端的WebHook收到一則訊息,但LINE 2022/5/13 增加了此功能之後,postbackAction多了兩個重要的屬性,分別是inputOption與fillInText。

inputOption可以是底下的值:

  • closeRichMenu: 關閉 rich menu
  • openRichMenu: 開啟 rich menu
  • openKeyboard: 開啟輸入鍵盤
  • openVoice: 開啟語音輸入

而 fillInText 則是當inputOption為openKeyboard時,開啟的文字輸入鍵盤中的預設文字。

例如,當建立 postbackAction 的程式碼如下:

Actions.Add(new  isRock.LineBot.PostbackAction() 
{
label  =  "開鍵盤",
data  =  "openKeyboard",
displayText  =  "開鍵盤",
fillInText  =  "預設文字",
inputOption  =  "openKeyboard"
});

則用戶點選該選單後,結果如下:
enter image description here

當您建立 postbackAction 的程式碼如下:

Actions.Add(new  isRock.LineBot.PostbackAction() 
{
label  =  "開選單",
data  =  "openRichMenu",
displayText  =  "開選單",
inputOption  =  "openRichMenu"
});

則用戶點選該PostbackAction選項,結果如下:
enter image description here

你還可以透過底下指令,來開啟語音輸入:

Actions.Add(new  isRock.LineBot.PostbackAction() 
{
label  =  "開語音輸入",
data  =  "openVoice",
displayText  =  "開語音輸入",
inputOption  =  "openVoice"
});

執行結果如下:
enter image description here

很有趣吧,這功能可以讓你的LINE Bot與用戶的互動更加的便捷, .net core 的範例程式碼在底下:
https://github.com/isdaviddong/ExLineRichMenuautomaticOpeningAndClosing

你只需要將 LineBotSDK 升級到 2.5.33-beta 以上的版本即可。

2022年5月13日 星期五

Azure DevOps 中的 Release Gate

enter image description here
在使用自動化上版的過程當中,你大概或多或少會想要使用簽核(Approval)的功能。簽核功能讓你可以自動佈署到特定站台(例如正式機)之前,形成一個 “把關” 的功能。

雖然感覺用起來很酷,但坦白說,我們對於上新版程式前的Approval行為,在態度上是不鼓勵的。因為多年下來,並沒有案例顯示,上版前的簽核真能夠減少什麼風險或是降低問題發生的機率。反倒是常常因為Approver卡住流程,造成自動化效率的降低。

如果企業是為了要有人負責,才配置這個Approver,那我們就更不鼓勵了。因為大部分的Approver其實無法在上版前真的做什麼檢查,常常有簽核權限的PM只是回頭問問工程師 : 『可以上正式機了嗎? 可以? 那我就按"同意"了唷』。這樣的橡皮圖章其實讓人很心酸。

事實上,大部分能做該做的檢查,根本早就在(也應該要在)自動化流程中被完成,而非靠人工的檢核。

更好用的機制 - Release Gate

比起Approvals的設定,Release Gate其實是配合自動化部署更好的選擇。

設定的方式類似 Approvals,只需要先將選項設為 Enabled即可啟動(下圖A),接下來就是設定要作為Gate的機制(下圖B):
enter image description here

按下Add之後,你可以選擇要作為Gate的機制:

enter image description here

系統已經內建不少的Gate類型可供選擇,其中比較常用的大概是『Invoke REST API』和『Query work items』。另外『SonarCloud Quality Gate』則是外掛的套件,配合SonarCloud軟體品質掃描用的。

當你設定了Release Gate這個機制,它將會每隔幾分鐘(最少五分鐘)檢查一次你設定的條件,當該條件成立的時候,才會允許Pipeline繼續往下進行。

這個功能可以幫助我們,在自動化的過程中減少不需要的人力介入或簽核,即可自動檢查特定條件是否成立。你也可以撰寫Azure Function,或是使用Invoke REST API方法來呼叫特定API,取得回傳值,以判斷是否可以讓Release Pipeline繼續往下運行。

在高強度(一天數次或一周數次)的頻繁交付過程中,Release Gate比起人工簽核(Approval)更是合作上版前的自動化關卡檢查機制。

來,以後試著放棄橡皮圖章吧。


參考資料:
Azure DevOps 顧問實戰
https://www.tenlong.com.tw/products/9786263241251?list_name=b-r7-zh_tw

2022年4月27日 星期三

Azure DevOps in Action - 建立Linux環境的Build Agent

Azure DevOps也可以輕易地建立在Linux環境上的Build Agent,底下我們將會採用Ubuntu的VM環境來示範這個動作。

首先,我們建議您用Azure上的Ubuntu 20.04虛擬機範本,相關的建立參數如下:
enter image description here
我採用D4s_v3的虛擬機等級,在East Asia資料中心建立該伺服器。同時為了讓我能夠從Windows環境連上該伺服器做後續設定,我選擇了開啟SSH(22) Port。

請牢記你建立時所輸入的帳號密碼。

在虛擬機建立完之後,可以透過PowerShell(我是使用 Windows Terminal)以ssh指令來連上該伺服器,並且輸入密碼:

ssh 帳號@IP

例如:
enter image description here

遠端登入成功之後,即可對該伺服器下達指令。

先整理一下我們登入後要做的事情,分別是:

  1. 安裝 .net core SDK(為了可以進行 dotnet build)
  2. 下載Azure DevOps Agent套件(壓縮檔)
  3. 解壓縮套件
  4. 安裝套件並進行設定(過程中需用到PAT)
  5. 執行Agent

整個動作,可以從Azure DevOps的Orgnization Settings開始:
enter image description here
從Orgnization Settings選單點選Agent Pools,選擇Default(即為Self-Hosted Agent),接著點選New Agent。

在出現的畫面中,請點選Linux,你會看到安裝Linux Build Agent的步驟:
enter image description here
首先,請點選上圖A的部分,複製agent套件的下載位置,在筆者截稿時,該位置為:

https://vstsagentpackage.azureedge.net/agent/2.202.1/vsts-agent-linux-x64-2.202.1.tar.gz

接著,請在powershell以ssh連線的ubuntu環境中,下達底下指令:

mkdir myagent && cd myagent

這會建立一個myagent資料夾,並且進入該資料夾中。

接著,請執行底下指令,來下載agent:

curl -O https://vstsagentpackage.azureedge.net/agent/2.202.1/vsts-agent-linux-x64-2.202.1.tar.gz

其中 curl -O 是下載檔案,而後面的url,請換成您剛才在上圖A中所複製到的最新版URL。

接著,再透過底下指令解壓縮:

tar zxvf vsts-agent-linux-x64-2.202.1.tar.gz

完成後,執行ls指令,會看到類似底下這些內容:
enter image description here
這樣我們待會就可以進行設定了。

但在此之前,我們得先準備好PAT(Personal Access Token),以及為該伺服器準備 .net core sdk環境。

參考 https://docs.microsoft.com/zh-tw/dotnet/core/install/linux-ubuntu 的說明,您可以透過運行底下指令,來安裝 .net core sdk:

wget https://packages.microsoft.com/config/ubuntu/21.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
sudo dpkg -i packages-microsoft-prod.deb
rm packages-microsoft-prod.deb

sudo apt-get update;
sudo apt-get install -y apt-transport-https &&
sudo apt-get update &&
sudo apt-get install -y dotnet-sdk-6.0

過程中可能會需要您輸入密碼,請在powershell中執行上述指令,結果類似底下這樣:
enter image description here
若你需要安裝其它版本的.net core sdk,可以修改上面指令中的版號即可,例如:

sudo apt-get install -y dotnet-sdk-5.0

成功安裝後,我們就要進行最後一個步驟了。

請先準備好PAT,取得PAT的方式如下,請先點選Azure DevOps畫面右上角個人帳號旁邊的小人圖示:
enter image description here
接著在選單中選擇 『Personal access token』,即會出現建立PAT的畫面:
enter image description here
在出現的畫面中選擇建立新的PAT。

PAT是替代你的帳號密碼的令牌,在你指定的有限時間內,出示該令牌就等於具有你所賦予的權限。

建立好了之後,請保留該PAT,它的長像大概是底下這樣:

zs4l6xp7xwhnj7lp8ta7i4q3xhtfasaxs3vp6xxwrj6iger7i63ob2eq

接著,請回到剛才的powershell視窗,在myagent資料夾底下執行:

./config.sh

執行過程中,會需要輸入PAT:
enter image description here
請留意,上圖2中的URL,要輸入的是你的Azure DevOps站台位置,而輸入PAT之前(上圖3),會先要你按一個Enter(請仔細注意上面的英文敘述),然後才是輸入PAT(按下滑鼠右鍵即可貼上)。

後面的幾個選項都按Enter即可,完成後,你會看到Setting Saved.

接著,再執行 ./run.sh ,你會發現,系統已經開始運作,並且在等待jobs了 :
enter image description here
這時候,你就可以使用這個 agent pool來進行build job了。

你可以依照先前我們介紹過的方式,建立一個 .net core 程式的CI Build Pipeline,唯一不同的地方是,這次(下圖1)Agent Pool選擇的是Default(Private) ,其它的設定均不變:
enter image description here
當你運行該Pipeline時,會發現,這個Build Machine比Azure DevOps內建的來的快很多,自然是因為這台VM我們建立時選擇的等級是很高檔的。

沒多久,整個CI Build就順利的完成了:
enter image description here
你也會看到,PowerShell中,Ubuntu的Command Line出現相對應的提示訊息:
enter image description here
表示job被成功的完成了。

如果要停止該agent,可以在命令列按下CTRL+C,如果要移除該agent,只需要下達 ./config.sh remove指令,並輸入PAT即可:
enter image description here
建立一個私有的Linux Build Agent就是這麼簡單。

相關資源:

[書籍]Azure DevOps顧問實戰:
https://www.tenlong.com.tw/products/9786263241251?list_name=b-r7-zh_tw

[課程]敏捷開發專案管理與Azure DevOps實戰
https://www.studyhost.tw/NewCourses/ALM

2022年4月26日 星期二

No hosted parallelism has been purchased or granted.

近期上課時,許多學員在申請好Azure DevOps站台後,使用Build Pipeline時,可能會發現它發生了類似底下這樣的錯誤訊息:
enter image description here
完整的錯誤訊息是:

##[error]No hosted parallelism has been purchased or granted. To request a free parallelism grant, please fill out the following form https://aka.ms/azpipelines-parallelism-request

這段錯誤訊息的起因,是由於2021年3月之後,微軟已經取消了預設的免費pipeline使用,若您要使用免費的pipeline,必須依照上述的訊息,填寫申請表(網址如下):
https://aka.ms/azpipelines-parallelism-request

經過同學測試,如果申請成功,你會收到微軟寄來的信件,告知您已經可以使用。但因為填寫申請表曠日廢時(大概要2-3個工作天),若您不想等待,我們還有一個更簡單(但可能需要點費用)的方法。你可以用登入Azure DevOps相同的帳號,申請一個免費的Azure Trial訂閱,接著將該訂閱綁定於Azure DevOps服務即可:
enter image description here
當成功設定好訂閱(Subscription)連結之後,您必須將Paid parallel jobs設定為1(參考下圖):
enter image description here
設定完成儲存之後,立即可以使用Pipeline

特別注意,每一個 Paid parallel jobs 可能會花費 $40USD唷,請特別留意費用的產生。

2022年3月3日 星期四

使用IoC與DI有何意義? (四) 使用IoC與DI提高可測試性

enter image description here這一系列的文章,持續維持著一年更新一篇的進度,😛。

今天適逢良辰吉日,我們再次來談談,如何透過IoC與DI增加系統的可測試性。

關於單元測試(Unit Test)

我們知道,有單元測試的存在,我們得以放膽的修改程式碼,無須擔心程式碼的頻繁異動將造成意料之外的副作用。

也因此,有一些團隊追求著程式碼單元測試的覆蓋率。

然而,高覆蓋率的單元測試並不意味著就會有更高品質的程式碼,反而真正重要的是,如何為我們系統中的核心邏輯、重要的核心函式,適當的添加單元測試。

所以,我們接下來要來談一談,如何透過IoC與DI增加程式碼的可測試性。

關於可測試性

你大概也已經知道,我們可以透過Visual Studio為特定的method來建立單元測試。特別是重要的商業邏輯運算函式、或是API,都是單元測試非常能發揮功能的好對象。

然而,你可能會發現有些程式碼似乎難以測試,例如底下這個例子:

Console.Write("請輸入金額(USD):");
var amount = int.Parse(Console.ReadLine()); //100
Console.Write("請輸入人數:");
var people = int.Parse(Console.ReadLine()); //5
Financy f = new Financy();
var CostByPeople = f.SplitMoney(amount, people);
Console.Write(CostByPeople);

上面這段程式碼看起來簡單,實際上,也真的很簡單😎。

SplitMoney()是一個計算旅遊消費金額分攤的函式。

假設,你和一夥人出國旅遊,在路邊店家吃了一餐,總共100美元,你想計算每個人要負擔多少台幣,就可以使用這個函式。呼叫SplitMoney()時,傳入『美金總金額』和『人數』兩個參數,它就幫你算出一個人要付的台幣金額。

假設我們要針對這個函式進行單元測試,乍看之下似乎並不難,但我們看SplitMoney()的具體內容:

public class Financy
{
  public double SplitMoney(double USDAmount, int People)
  {
    var currencyConverter = new CurrencyConverter();
    //使用到外部函式(抓取匯率)
    double rate = currencyConverter.Convert("USD",  "TWD");
    //計算台幣總金額
    double Total = USDAmount * rate;
    //回傳一個人需要付多少錢(台幣)
    return Total / People;
  }
}

這下問題來了。

我們SplitMoney()這個方法本身不難,也不過就是把總金額除以旅遊人數,就算出平均金額了。倘若我們需要為SplitMoney()這個方法撰寫單元測試,似乎也沒啥問題。

但這邊出現了個障礙,你知道的,單元測試是以程式來驗證程式,也就是說,我要從外部來驗證一個函式是否正確,就撰寫單元測試函式,來呼叫我想驗證的函式,傳入固定的參數,我想驗證的函式理當也會有著同樣固定的回傳結果。藉由判斷回傳結果是否與預期的一致,我就可以驗證該函式是否正確。

但剛才說,這邊出了點問題,因為SplitMoney()這個方法在計算的過程中呼叫到了Convert這個函式:

//使用到外部函式(抓取匯率)
double rate = currencyConverter.Convert("USD", "TWD");

上面這個方法,抓取的是『即時』的匯率,而因為匯率是浮動的,這表示,當我們每一次呼叫這個函式時,即便傳入的,是同樣的參數,也可能得到不同的結果!

如此一來,該函式SplitMoney()就沒有可測試性(testability),因為我們無法去驗證它,是否在被修改後,還維持著一致的運算邏輯。

該如何解決前面提到的問題?

使用fake類別提高可測試性

我們先釐清問題在哪,顯然,問題的來源不是來自於SplitMoney()這個方法本身,而是來自於SplitMoney()這個方法執行的過程中,所呼叫的即時匯率抓取函式。

倘若,我們能夠在執行單元測試方法時,也就是運行掛載著[TestMethod()] 這個attribute的單元測試方法時,將SplitMoney()中抓取即時匯率的函式給換掉,改成永遠回傳固定值(例如台幣與美金的兌換永遠維持在 27:1),如此一來,我們的單元測試函式,就可以撰寫了,因為我們每次重複呼叫時,都可以得到一個穩定的預期結果值。

不過,我們在執行單元測試的時候,雖然抓取的匯率必須是固定的值,但一般呼叫的時候,則必須要保持是抓取到動態的匯率才行呀。

為了實現這個功能,我們可以針對SplitMoney()中所用到的抓取匯率的這個類別,設計一個相同的偽裝類別(Fake Class)。為了這麼做,我們先把抓取匯率的這個類別CurrencyConverter抽提出介面ICurrencyConverter,同時調整一下原本的CurrencyConverter類別,讓它繼承自介面ICurrencyConverter:

   public interface ICurrencyConverter
   {
     float Convert(string From, string To);
   }
   
   public class CurrencyConverter : ICurrencyConverter
   {
      public float Convert(string From, string To)
      {
         //…具體程式碼請參考 github
         // https://github.com/isdaviddong/HOL-UnitTestWithIoC_After
         return data;
      }
   }

然後,再繼承ICurrencyConverter介面設計出一個fake類別:

//建立fake類別
public class FakeCurrencyConverter : ICurrencyConverter
{
   public float Convert(string From, string To)
   {
      return 27.67222F;
   }
}

你會發現,我們在假類別中,把匯率固定在27.6,如此一來,倘若我們在單元測試方法中,可以讓SplitMoney()採用這個假類別FakeCurrencyConverter,而非使用真的CurrencyConverter類別去抓取即時匯率,那就可以在單元測試方法中,維持SplitMoney()回傳值的穩定性(冪等性)。如此一來,就可以正確的撰寫單元測試了。

那我們要怎麼讓單元測試中的程式碼在呼叫SplitMoney()方法的時候,採用假類別,而一般程式碼呼叫SplitMoney()方法的時候,卻又使用真的類別呢?

請注意,這時候,建構子注入就要出現了。

透過IoC與DI提高可測試性

就物件導向程式設計的概念來說,如果A方法對於B類別有依賴,我們可以幫B類別設計(重構出)一個介面C,將A方法程式碼中對於B類別的依賴,改寫成對介面C的依賴。

這其實,就是剛才我們做的事情。

我們對SplitMoney()所倚賴的類別CurrencyConverter進行重構,為它建立介面ICurrencyConverter,並且繼承該介面建立出一個類似CurrencyConverter類別的假類別FakeCurrencyConverter。

這樣有何好處?

如此一來,我們可以調整原本SplitMoney()方法的程式碼,把寫死依賴CurrencyConverter類別的這個狀況,改為依賴介面ICurrencyConverter:

ICurrencyConverter _CurrencyConverter;

public double SplitMoney(double USDAmount, int People)
{
   //var currencyConverter = new CurrencyConverter();
   //使用到外部函式(抓取匯率)
   double rate = _CurrencyConverter.Convert("USD", "TWD");
   //計算台幣總金額
   double Total = USDAmount * rate;
   //回傳一個人需要付多少錢(台幣)
   return Total / People;
  }

然後,在建立該類別的時候,把_CurrencyConverter先預設設定為CurrencyConverter類別即可。

這樣做的好處是,有需要時,我們可以動態替換抓取匯率的類別,將其改成fake類別,以便於固定抓取到的匯率回傳值。進而讓SplitMoney()方法的計算結果冪等,好讓我們可以撰寫單元測試。

因此,我們依照上面的邏輯,把程式碼改成底下這樣,實現所謂的建構子注入:

public class Financy
{
   //加入建構子注入
   ICurrencyConverter _CurrencyConverter;
   public Financy(ICurrencyConverter currencyConverter)
   {
      _CurrencyConverter = currencyConverter;
   }

   public Financy()
   {
      //預設狀況下,用標準類別
      _CurrencyConverter = new CurrencyConverter();
   }

   public double SplitMoney(double USDAmount, int People)
   {
      //var currencyConverter = new CurrencyConverter();
      //使用到外部函式(抓取匯率)
      double rate = _CurrencyConverter.Convert("USD", "TWD");
      //計算台幣總金額
      double Total = USDAmount * rate;
      //回傳一個人需要付多少錢(台幣)
      return Total / People;
   }
}

也就是說,我們在呼叫這個SplitMoney()方法前,在建立其所屬的類別Financy時,可以把將來要具體使用的抓取匯率的類別,以建構子參數的方式傳入,而不是寫死在SplitMoney()方法中。如此一來,我們就可以在運行單元測試的時候,採用fake類別:

[TestClass()]
public class FinancyTests
{
   [TestMethod()]
   public void SplitMoneyTest()
   {
      //注入測試用的fake類別實作
      Financy f = new Financy(new FakeCurrencyConverter());
      var CostByPeople = f.SplitMoney(100, 5);
      Assert.IsTrue(CostByPeople.ToString().StartsWith("553.444"));
   }
}

而運行一般程式的時候,採用正常的類別(當沒有傳入建構子參數,則預設使用一般類別):

Console.Write("請輸入金額(USD):");
var amount = int.Parse(Console.ReadLine()); //100
Console.Write("請輸入人數:");
var people = int.Parse(Console.ReadLine()); //5
Console.ReadLine();
//採用正常的類別
Financy f = new Financy();
var CostByPeople = f.SplitMoney(amount, people);

這樣一來,是不是讓原本不易撰寫測試程式的程式碼,變成可以輕易測試了呢? 這就是可測試性(testability)的提升。

如果你需要程式碼,請參考:
https://github.com/isdaviddong/HOL-UnitTestWithIoC_After


本文內容來自於『團隊開發與架構設計實務』課程,我們最近要開課囉,依照過去經驗這門課幾乎都是秒殺,如果你需要預先保留席次,請點選這裡登記唷。

若您要詢問問題,或是需要即時取得更多相關訊息,可按這裡加入FB專頁。
若這篇文章對您有所幫助,請幫我們分享出去,謝謝您的支持。

2022年2月23日 星期三

Azure DevOps in Action - 脫離組織

你知道的,有些地方,進去很容易,脫離就有點困難。
我說的不是黑道堂口,也不是邪教異端,我說的是 Azure DevOps organization。

不只一次,我被問過這個問題:『當被加入一個Azure DevOps組織之後,要怎麼離開呀?』

沒錯,你尋遍整個portal,沒有離開的選項。也就是說,倘若該組織的admin不把你移除,你似乎永遠會屬於某個組織,這導致於,每次你登入的時候,左方選單裡面就有一大多你根本已經不會去用的組織站台:
enter image description here

這些站台多還不打緊,它還讓我無法建立新的組織:
enter image description here

這使得我下定決心,要脫離組織的綑綁。
尋找了一會兒,發現,原來還是可以脫離組織的,但這功能不在portal上,而是在 https://aex.dev.azure.com/ 這個頁面:
enter image description here

在這個畫面上會列出你的帳號參與了哪些組織。
原來,在這個畫面,只要展開你不是owner的組織,右下角就會有一個 Leave 聯結按紐,把它給點下去,出現了警告訊息:
enter image description here

但,這就是我要的呀。
點選 Leave 後,徹底脫離組該織的所有的掌控與專案了。

熱門文章