持續集成持續部署持續交付_如何開始進行持續集成

持續集成持續部署持續交付

Everything you need to know to get started with continuous integration: branching strategies, tests automation, tools and best practices.

開始進行持續集成所需的一切:分支策略,測試自動化,工具和最佳實踐。

目標:快速安全地交付工作代碼 (The goal: Deliver working code quickly and safely)

The goal of Continuous Integration is to deliver code to the main branch of your repository:

持續集成的目標是將代碼交付到存儲庫的主分支:

  • Quickly: from pushing new code to the repository to merging it to the main branch when it works should be done within minutes

    快速:從新代碼推送到存儲庫到工作時將其合并到主分支,應在幾分鐘內完成
  • Safely: how do we know the new code works? Continuous Integration is about setting up the right checks to merge code automatically in full confidence

    安全地:我們如何知道新代碼有效? 持續集成是指設置正確的檢查以完全自信地自動合并代碼

Continuous Integration is a bit about tools and a lot about mindset and culture in the team. You want your development process to facilitate fast integration of new code while keeping a working main branch at all times. This working main branch will enable Continuous Delivery or Continuous Deployment in the future. But these are for another post. Let’s focus on Continuous Integration first.

持續集成與工具有關,與團隊中的觀念和文化息息相關。 您希望您的開發過程能夠促進新代碼的快速集成,同時始終保持主分支正常工作。 這個工作的主要分支將在將來啟用持續交付或持續部署。 但是這些是另一篇文章。 讓我們首先關注持續集成。

There are 2 pillars to achieve Continuous Integration:

實現持續集成有兩個Struts:

小塊工作 (Work in small chunks)

Imagine a team of 5 working on a SaaS product. Each of them develops a separate new feature. The workload on each feature is about 1 or 2 weeks. There are 2 ways to go here.

想象一下一個由5人組成的團隊在研究SaaS產品。 他們每個人都開發一個單獨的新功能。 每個功能的工作量約為1或2周。 這里有2種方法。

  • The team could go with feature branches. Each developer will work on their part on a “feature branch”. The branches will be merged to the main branch once everyone is happy with their work

    團隊可以使用功能分支。 每個開發人員都將在“功能分支”中工作。 每個人對工作滿意后,分支將合并到主分支
  • The team could go with branches (still) but integrate their work to the main branch on every push. Even if things are still a work in progress! The work in progress would remain invisible to any end user or tester of the main branch

    該團隊可以(仍然)使用分支機構,但每次推送時都將其工作集成到主分支機構中。 即使事情仍在進行中! 正在進行的工作對于主分支的任何最終用戶或測試人員將不可見

Which approach do you think will work best?

您認為哪種方法最有效?

The first approach will ultimately lead to the “unpredictable release syndrome”. Long lived feature branches create a false sense of safety and comfort for each developer individually. As the branches drift apart for a long period of time, there is no way to measure how hard it will be to merge it all. At best some minor code conflicts will arise, at worst fundamental design assumptions will be challenged and things will have to be reworked … the hard way.

第一種方法最終將導致“不可預測的釋放綜合癥”。 長期存在的功能分支會給每個開發人員分別帶來錯誤的安全感和舒適感。 由于分支分散很長一段時間,因此無法衡量將所有分支合并的難易程度。 最好的情況是會出現一些較小的代碼沖突,最壞的情況是將挑戰基本的設計假設,并且必須重做……這是艱難的方法。

Rework will be done under time pressure, leading to a drop in quality and accumulation of technical debt. This is a vicious circle.

返工將在時間壓力下進行,從而導致質量下降和技術債務累積。 這是一個惡性循環。

See the post about Why you should not use feature branches for the dirty details.

有關骯臟的詳細信息,請參閱有關為何不應該使用功能分支的文章。

The second approach is what we need to enable continuous integration. Each developer does work on their own branch. Difference is:

第二種方法是我們需要進行持續集成。 每個開發人員都在自己的分支上工作。 區別是:

Changes are merged to the main branch on every push, and each developer syncs their branch with latest main branch version a few times a day.

每次推送時,更改都會合并到主分支中,并且每個開發人員每天都會幾次將其分支與最新的主分支版本同步。

This way the team can fix conflicts and align design assumptions faster and easier. 5 small problems discovered early on are way better that 1 big problem discovered just before release day. Check out the “Feature Toggles” section below to see how you should integrate “work in progress” to the main branch.

這樣,團隊可以更快,更輕松地解決沖突并調整設計假設。 早期發現的5個小問題比發布前一天發現的1個大問題要好得多。 請查看下面的“功能切換”部分,以了解如何將“進行中的工作”集成到主分支中。

安全來自于自動檢查 (Safety comes with automated checks)

Ancient software development process was based on a build cycle followed by a test cycle. And this would probably still fit the “feature branches” approach described above. If we integrate and merge code tens of times a day, manual testing does not make sense. It would take too long. We need automated checks to verify that the code works properly. We need a CI tool that will take each developers’ push and run build and tests automatically.

古代軟件開發過程是基于構建周期和測試周期的。 而且這可能仍然適合上述“功能分支”方法。 如果我們一天要整合和合并代碼數十次,那么手動測試就沒有意義。 會花太長時間。 我們需要自動檢查以驗證代碼是否正常運行。 我們需要一個CI工具,該工具將接受每個開發人員的推送并自動運行構建和測試。

The test’s type and content should be:

測試的類型和內容應為:

  • fast enough to provide feedback to the developer within minutes

    足夠快地在幾分鐘內向開發人員提供反饋
  • thorough enough to merge the code to the main branch in full confidence

    足夠徹底地將代碼完全合并到主分支中

Unfortunately there is no one size fit all test type and content. The right balance is specific to your project. Do not run large and time consuming test suites during your CI phase. Such tests provide better safety but they come at the cost of a delayed feedback to the developers. This leads to context switching which is a pure waste of time.

不幸的是,沒有一種適合所有測試類型和內容的尺寸。 適當的平衡是針對您的項目的。 在CI階段,請勿運行大型且耗時的測試套件。 這樣的測試提供了更好的安全性,但是卻以延遲反饋給開發人員為代價。 這導致上下文切換,這純粹是浪費時間。

優化開發人員的時間并減少上下文切換 (Optimize developers’ time and reduce context switching)

Long CI checks, and by long I mean over 3 minutes, introduce a compound waste of time for each developer in your team. Let’s compare a “good” and a “bad” worklow.

冗長的CI檢查(很長時間(平均超過3分鐘))會給您團隊中的每個開發人員造成時間上的浪費。 讓我們比較一下“好”和“壞”的工作流程。

The “good” workflow:

“良好”的工作流程:

  • You commit and push your code

    您提交并推送您的代碼
  • The CI build and tests run for 1 to 3 minutes

    CI構建和測試運行1-3分鐘
  • During the 1 to 3 minutes you review the task at hand, bump the status in some management tool, or review your code once again

    在1至3分鐘內,您將審閱手頭的任務,更改某些管理工具的狀態或再次審閱代碼
  • Within 3 minutes you get a successful status: you can move on to the next part of your task. If you get a failed build: you can fix the issue right away

    在3分鐘內,您將獲得成功的狀態:您可以繼續執行任務的下一部分。 如果構建失敗:您可以立即解決問題

The “bad” workflow:

“不良”工作流程:

  • You commit and push your code

    您提交并推送您的代碼
  • The CI build and tests run for 15 minutes

    CI構建和測試運行15分鐘
  • What do you do during these 15 minutes?

    您在這15分鐘內會做什么?
  • You could grab a cup of coffee with the team. Fair enough, but how many of these can you have per day?

    您可以和團隊一起喝杯咖啡。 足夠公平,但是您每天可以有多少個?
  • You would probably get your head on the next task in your pipeline

    您可能會著手處理管道中的下一個任務
  • 15 minutes later you get a failed build notification. You need to switch back to the previous task, try to fix the issue … and go for another 15 minutes loop …

    15分鐘后,您會收到失敗的構建通知。 您需要切換回上一個任務,嘗試解決該問題……然后再循環15分鐘……
  • At that point you are wondering: should I get back to this next task again or just wait the 15 minutes and achieve peace of mind that I am actually really done with my current task …

    那時,您想知道:我應該再回到下一個任務還是等待15分鐘,讓我放心,我實際上已經完成了當前任務……

The bad workflow is not only a waste of time. It is also frustrating for developers. And productive developers are happy developers.

糟糕的工作流程不僅浪費時間。 這也讓開發人員感到沮喪。 生產性開發人員是快樂的開發人員。

You need to align your tools and workflows to keep your developers happy.

您需要調整工具和工作流程,以使開發人員滿意。

工具類 (Tools)

分枝 (Branching)

Continuous Integration is about integrating code from different developers’ branches to a common branch in your configuration management system. Chances are you are using git. In git the default main branch in a repository is called “master”. Some teams create a branch called “develop” as the main branch for continuous integration. They use “master” to track deliveries and deployments (develop being merged to master).

持續集成是將代碼從不同開發人員的分支集成到配置管理系統中的公共分支。 您可能正在使用git。 在git中,存儲庫中的默認主分支稱為“ master”。 一些團隊創建一個名為“ develop”的分支作為持續集成的主要分支。 他們使用“母版”來跟蹤交付和部署(將開發內容合并到母版中)。

You probably already have a main branch your team pushes or merges code to. Stick with it.

您可能已經有一個主要分支,您的團隊將代碼推送或合并到該分支。 堅持下去。

Each developer should work on their own branch. One can use multiple branches if working on many different topics at once. Although this would be a sign of “unfocused” work at best. As soon as a consistent part of your code is ready, push your repository. The CI checks will kick in and merge your code to the main branch if they are successful. If the checks fail, you are still on your own branch and can fix whatever needs to be fixed and push again.

每個開發人員都應該在自己的分支上工作。 如果一次處理多個不同的主題,則可以使用多個分支。 盡管這充其量是最好的“無重點”工作的標志。 一旦代碼的一致部分準備就緒,請推送您的存儲庫。 如果成功,CI檢查將啟動并將您的代碼合并到主分支。 如果檢查失敗,則您仍在自己的分支上,可以修復需要修復的任何內容并再次推送。

The important word in the process above is consistent part of your code. How do you know it is consistent? Simple.

上面過程中的重要單詞是代碼的一致部分 。 您怎么知道它是一致的? 簡單。

If you can easily come up with a good commit message, it’s consistent.

如果您可以輕松提出一個好的提交消息,那么它是一致的。

On the other hand if your commit message needs 3 bullets and many adjectives and adverbs, it’s probably not good. Split your work in multiple, consistent commits. And then push the code. Consistent commits help code reviews and make the repository history easier to follow.

另一方面,如果您的提交消息需要3個項目符號以及許多形容詞和副詞,則可能不是很好。 將您的工作分成多個一致的提交。 然后推送代碼。 一致的提交有助于代碼審查,并使存儲庫歷史記錄更易于遵循。

Don’t just push whatever because it’s the end of the day!

不要僅僅因為它已經結束而推動任何事情!

拉取要求 (Pull requests)

What is a pull request? A pull request is a concept in which you ask the team to merge your branch to the main branch. The acceptance of your request should go through a status provided by your CI tool and potentially a code review. Ultimately the manual acceptance of a human being in charge of merging the pull requests.

什么是拉取請求? 拉取請求是一個概念,在該概念中,您要求團隊將您的分支合并到主分支。 接受請求應經過CI工具提供的狀態,并可能需要進行代碼審查。 最終,人工負責合并合并請求請求的人員。

Pull requests were born in open source projects. Maintainers needed a structured way to evaluate contributions before merging them in. Pull requests are not part of Git. They are supported by any Git provider, though (GitHub, BitBucket, GitLab, …).

拉取請求誕生于開源項目中。 維護人員需要一種結構化的方法來評估捐款,然后再將其合并。拉取請求不屬于Git。 但是,任何Git提供程序都支持它們(GitHub,BitBucket,GitLab等)。

Note that pull requests are not mandatory for Continuous Integration. Their main benefit is to support a code review process, which cannot be automated by design.

請注意,對于持續集成,拉取請求不是必需的。 它們的主要好處是支持無法通過設計自動執行的代碼審查過程。

If you are using pull requests, the same principles of “work in small chunks” and “optimize developers time” apply:

如果您使用拉取請求,則“小塊工作”和“優化開發人員時間”的相同原則適用:

  • keep each pull request small and with one clear purpose (it will make code review way easier)

    將每個拉取請求保持較小且有一個明確的目的(這將使代碼查看方式更容易)
  • keep your CI checks fast

    保持您的CI快速檢查

自動檢查 (Automated checks)

The heart of your Continuous Process are automated checks. They ensure that the main branch code is working properly after your code is merged. If they fail, your code does not get merged. As a minimum the code should compile or transpile or whatever your tech stack is doing to make it ready for runtime.

連續流程的核心是自動檢查。 他們確保在合并代碼后,主分支代碼可以正常工作。 如果它們失敗,則不會合并您的代碼。 至少,該代碼應可以編譯或轉譯,或者您的技術堆棧正在做什么,以使其可以運行時就緒。

On top of compilation you should run automated tests to ensure the software works properly. The better the test coverage, the better confidence you can have in the new code being merged to the main branch. Careful though! Better coverage means more tests and longer execution time. You need to find the right tradeoff.

在編譯之上,您應該運行自動化測試以確保軟件正常運行。 測試范圍越好,您對合并到主分支的新代碼的信心就越大。 小心點! 更好的覆蓋范圍意味著更多的測試和更長的執行時間。 您需要找到正確的權衡。

Where do you start when you have no tests at all or need to cut down on some long running tests? Focus on what is critical for your project or product.

當您根本沒有測試或需要減少一些長期運行的測試時,您從哪里開始呢? 將重點放在對您的項目或產品至關重要的方面。

If you are building a SaaS application, you should check that users can sign up or login, and perform the most basic operations your SaaS provides. Unless you are developing a Salesforce competitor, you should be able to run your tests within minutes if not seconds. If you are building a heavy data processing backend: use limited data sets to exercise the different building blocks. Keep long running runs on large data sets out of Continuous Integration. Long running tests can be triggered after code is merged.

如果要構建SaaS應用程序,則應檢查用戶是否可以注冊或登錄,并執行SaaS提供的最基本的操作。 除非您正在開發Salesforce競爭對手,否則您應該能夠在幾分鐘甚至幾分鐘內運行測試。 如果您要構建大量的數據處理后端,請使用有限的數據集來練習不同的構建基塊。 在大型數據集上保持長期運行,而不會進行持續集成。 合并代碼后,可以觸發長時間運行的測試。

專業提示 (Pro Tips)

功能切換 (Feature toggles)

The key concept of Continuous Integration is to put your code in the main branch as soon as possible. Even work in progress. Even features that do not fully work or that you don’t want exposed to testers or end users. The way to achieve that is to use feature toggles. Have your new feature under an enabled/disabled toggle. The toggle can be a compile time boolean flag, an environment variable or a runtime thing. The right approach depends on what you want to achieve.

持續集成的關鍵概念是盡快將代碼放入主分支。 甚至正在進行中。 甚至某些功能無法完全使用,或者您也不想暴露給測試人員或最終用戶。 實現此目的的方法是使用功能切換。 在啟用/禁用切換下啟用新功能。 切換可以是編譯時布爾標志,環境變量或運行時事物。 正確的方法取決于您要實現的目標。

The first major benefits of feature toggles is that you can take them up to production and enable/disable the new feature upon need. You could restart a server with a changed environment variable, or toggle on/off a new UI dashboard layout. This way you have full flexibility to roll out the feature. Or disable it if causes unexpected issues in production. Or allow end users to opt in or out of the feature (in case of the UI toggles).

功能切換的第一個主要好處是您可以將其投入生產并根據需要啟用/禁用新功能。 您可以使用更改后的環境變量重新啟動服務器,也可以打開/關閉新的UI儀表板布局。 這樣,您就可以完全靈活地推出該功能。 如果在生產中導致意外問題,請禁用它。 或允許最終用戶選擇啟用或退出功能(在UI切換的情況下)。

The second major benefit of feature toggles is that they force you to think of the boundary between what you are doing and the existing code. This is a good exercise and this is what you should start with anyway every time you make an addition to an existing system. The feature toggle step makes this step of the process more visible.

功能切換的第二個主要優點是,它們迫使您考慮正在執行的操作與現有代碼之間的界限。 這是一個很好的練習,這是每次添加到現有系統后都應該從頭開始的事情。 功能切換步驟使該過程的步驟更加明顯。

The only drawback on feature toggles is that you need to clean them up periodically from the environment and from the code. Once a feature is battle tested and adopted by users, it should be the default. The code for the toggle and the old version of things (if any) should be cleaned up. Don’t fall into the trap of a “configuration as toggles” system. The pitfall is that you will never be able to maintain and test all combination of the toggles and will have a fragile architecture in the end.

功能切換的唯一缺點是您需要定期從環境和代碼中清除它們。 一旦功能經過實戰測試并被用戶采用,則應將其作為默認功能。 切換代碼和舊版本的東西(如果有的話)應該清除。 不要陷入“切換配置”系統的陷阱。 陷阱是您將永遠無法維護和測試所有切換組合,并且最終將擁有脆弱的架構。

將CI建立時間保持在3分鐘以下 (Keep CI build time under 3 minutes)

Remember the “good” and the “bad” workflow in the first part of the article. We want to avoid context switching for developers. Pick your phone and set a 3 minutes timer on. See how long it is when you are just waiting for something! 3 minutes should be an absolute maximum for you to focus and move safely and efficiently from one task to the other.

記住本文第一部分中的“好”和“壞”工作流程。 我們希望避免為開發人員切換上下文。 拿起手機,并設置3分鐘計時器。 看看等待什么時間! 3分鐘絕對是您最多的絕對時間,您可以集中精力并安全有效地將其從一項任務轉移到另一項任務。

A build under 3 minutes might seem crazy to some teams, but it is definitely achievable. It has more to do with how you organize your work than the tools you use. Ways to optimize your build are:

3分鐘以內的構建對于某些團隊來說似乎是瘋狂的,但這絕對是可以實現的。 與您使用的工具相比,它與您組織工作的方式更多有關。 優化構建的方法是:

  • Use more build capacity: if you don’t have enough concurrent builds on your CI tool and builds get queued, developers lose time

    使用更多的構建能力:如果您的CI工具沒有足夠的并行構建,并且構建排隊,開發人員將浪費時間
  • Leverage caching: most tech stacks require you to install and configure dependencies when running a fresh build. Your CI tool should be able to cache these steps when dependencies do not change to optimize build time

    利用緩存:大多數技術堆棧都要求您在運行全新構建時安裝和配置依賴項。 當依存關系不改變時,您的CI工具應該能夠緩存這些步驟,以優化構建時間
  • Review your tests: check that your tests are optimized for time. Remove timeouts and “safely long” waiting steps. If you have heavy tests suites to run, consider moving them on a separate build that is run after the merge to the main branch. They would not be part of the Continuous Integration safeguard anymore, but heavy tests should not be anyway

    查看測試:檢查測試是否針對時間進行了優化。 刪除超時和“安全長”的等待步驟。 如果您要運行繁重的測試套件,請考慮將它們移動到合并到主分支后運行的單獨構建中。 它們不再是持續集成防護的一部分,但是無論如何都不應進行嚴格的測試
  • Split your code base: do you have to have everything in one repository? Do you have to build and run tests on everything even when some small part changes? There might be wins here.

    拆分代碼庫:是否必須將所有內容都存儲在一個存儲庫中? 即使某些小部分發生更改,您是否也必須對所有內容進行構建和運行測試? 這里可能會有勝利。
  • Run tests conditionally: run your tests only if some directories have changed. If your codebase is well organized, this can be a huge win

    有條件地運行測試:僅在某些目錄已更改的情況下運行測試。 如果您的代碼庫井井有條,這將是一個巨大的勝利

The great thing about forcing a short time limit on your CI checks is that it requires you to fundamentally improve your whole development process.

強制在較短的時間上進行CI檢查的好處在于,它要求您從根本上改善整個開發過程。

As Jim Rohn said:

正如吉姆·羅恩(Jim Rohn)所說:

“Become a millionaire not for the million dollars, but for what it will make of you to achieve it”.
“成為百萬富翁不是因為獲得了百萬美元,而是成為了您實現目標所能帶來的好處”。

虛擬合并:您的代碼本身并不重要 (The virtual merge: your code alone does not really matter)

Most Continuous Integration tools run the CI build on your branch to say if it can be merged or not. But that is not what is of interest here. If you know what you’re doing there is a pretty good chance that the code you have just pushed is working already! What your CI tool is supposed to verify is that your branch merged with the main branch works properly.

大多數持續集成工具會在您的分支機構上運行CI構建,以說明是否可以合并。 但這不是這里令人感興趣的。 如果您知道自己在做什么,那么您剛剛推送的代碼很有可能已經在工作! 您的CI工具應該驗證的是您的分支與主分支合并正常。

Your CI tool should perform a local merge of your branch to the main branch and run the build and tests against that. Your branch can then be automatically merged if the main branch does not change in the meantime. If it does change, the CI checks should be run again until your code can be safely merged. If your CI tools does not support this kind of workflow, change your tool.

您的CI工具應執行分支到主分支的本地合并,然后運行構建并對此進行測試。 如果主分支在此期間未更改,則分支可以自動合并。 如果確實發生更改,則應再次運行CI檢查,直到可以安全地合并代碼為止。 如果您的CI工具不支持這種工作流程,請更改您的工具。

邪惡的任務管理器 (The evil task manager)

There is a misbelief that it is cool to be able to trace the code related to a task in your Agile board or bug tracker like JIRA or similar. While it is a nice concept on paper, the impact on the development process is for sure not worth the effort. The task manager provides a “features and bugs” view of the world. The code is structured and layered in a very different way. Trying to reconciling an item in the task manager and a set of commits is pointless. If you want to know why a piece of code has been written, you should be able to get the information from the code context and comments.

令人懷疑的是,能夠在敏捷板或Bug跟蹤程序(例如JIRA或類似程序)中跟蹤與任務相關的代碼很酷。 盡管這是一個很好的概念,但對開發過程的影響肯定不值得付出努力。 任務管理器提供了世界的“功能和錯誤”視圖。 代碼以非常不同的方式進行結構化和分層。 試圖協調任務管理器中的項目和一組提交是沒有意義的。 如果您想知道為什么要編寫一段代碼,則應該能夠從代碼上下文和注釋中獲取信息。

最后的想法 (Final Thoughts)

Tools are only tools. Setting up the tools is probably a 1 hour thing. If you use them wrong though, you won’t get the expected results.

工具只是工具。 設置工具可能需要1個小時的時間。 如果您錯誤地使用它們,將無法獲得預期的結果。

Keep in mind the goals we set for ourselves for Continuous Integration:

請記住我們為持續集成設定的目標:

  • Deliver working code quickly and safely

    快速安全地交付工作代碼
  • Optimize developers’ time and reduce context switching

    優化開發人員的時間并減少上下文切換

The real deal is about shifting your mindset to “continuously deliver value” to your project or product.

真正的交易是改變思維方式,“為項目或產品“持續交付價值”。

Think of your software development process as a hardware production facility. Developers’ code represents the moving parts. The main branch is the assembled product.

將您的軟件開發過程視為硬件生產設施。 開發人員的代碼代表活動的部分。 主要分支是組裝產品。

The faster you integrate the different pieces together and check that things are working, the closer you are to have a working product at the end.

您將各個部分集成在一起并檢查工作是否正常的速度越快,最后獲得有效產品的可能性就越大。

A few practical examples:

一些實際的例子:

  • You are working on a new feature and have to change a low level component others will most likely use. Make a dedicated commit for that common component part and have it merge already. Then continue working on the rest of your feature. Other developers will be able to base their work on your change right away.

    您正在開發一項新功能,并且必須更改其他人最有可能使用的低級組件。 為此公用組件部分進行專用提交,并使其已經合并。 然后繼續處理其余功能。 其他開發人員將能夠立即根據您的更改進行工作。
  • You are working on a large feature that will require a lot of time and code? Use a feature toggle. Don’t work in isolation. Ever!

    您正在開發一項需要大量時間和代碼的大型功能嗎? 使用功能切換。 不要孤立地工作。 曾經!
  • You are waiting for a code review but no one is available to do it. If your code is passing the CI checks then just merge it and make the code review happen afterwards. If it sounds like breaking the process, remember that “done is better than perfect”. If it is working, it provides more value in the main branch than parked on the side for days.

    您正在等待代碼審查,但沒有人可以這樣做。 如果您的代碼通過了CI檢查,則只需合并它,然后再進行代碼檢查。 如果聽起來像要打破流程,請記住“做總比做得好”。 如果它可以正常工作,那么它在主分支機構中提供的價值要比在邊上停泊好幾天。

Thanks for reading! If you find the article useful please hit the clap button below. It would mean a lot to me and it helps other people see the story!

謝謝閱讀! 如果您發現該文章有用,請點擊下面的拍手按鈕。 這對我來說意義重大,而且可以幫助其他人看到這個故事!

Article originally published at fire.ci on April 9, 2019.

該文章最初于2019年4月9日在fire.ci上發表。

翻譯自: https://www.freecodecamp.org/news/how-to-get-started-with-continuous-integration-7b2f8d87c914/

持續集成持續部署持續交付

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/391730.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/391730.shtml
英文地址,請注明出處:http://en.pswp.cn/news/391730.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

51nod 1073約瑟夫環

思路傳送門 &#xff1a;http://blog.csdn.net/kk303/article/details/9629329 n里面挑選m個 可以遞推從n-1里面挑m個 然后n-1里面的x 可以轉換成 n里面的x 的公式 x &#xff08;xm&#xff09;%n; #include <bits/stdc.h> using namespace std;int main () {int n,m;s…

如何選擇優化算法遺傳算法_用遺傳算法優化垃圾收集策略

如何選擇優化算法遺傳算法Genetic Algorithms are a family of optimisation techniques that loosely resemble evolutionary processes in nature. It may be a crude analogy, but if you squint your eyes, Darwin’s Natural Selection does roughly resemble an optimisa…

robot:截圖關鍵字

參考&#xff1a; https://www.cnblogs.com/hong-fithing/p/9656221.html--python https://blog.csdn.net/weixin_43156282/article/details/87350309--robot https://blog.csdn.net/xiongzaiabc/article/details/82912280--截圖指定區域 轉載于:https://www.cnblogs.com/gcgc/…

leetcode 832. 翻轉圖像

給定一個二進制矩陣 A&#xff0c;我們想先水平翻轉圖像&#xff0c;然后反轉圖像并返回結果。 水平翻轉圖片就是將圖片的每一行都進行翻轉&#xff0c;即逆序。例如&#xff0c;水平翻轉 [1, 1, 0] 的結果是 [0, 1, 1]。 反轉圖片的意思是圖片中的 0 全部被 1 替換&#xff…

SVN服務備份操作步驟

SVN服務備份操作步驟1、準備源服務器和目標服務器源服務器&#xff1a;192.168.1.250目標服務器&#xff1a;192.168.1.251 root/rootroot 2、對目標服務器&#xff08;251&#xff09;裝SVN服務器&#xff0c; 腳本如下&#xff1a;yum install subversion 3、創建一個新的倉庫…

SpringCloud入門(一)

1. 系統架構演變概述 #mermaid-svg-F8dvnEDl6rEgSP97 .label{font-family:trebuchet ms, verdana, arial;font-family:var(--mermaid-font-family);fill:#333;color:#333}#mermaid-svg-F8dvnEDl6rEgSP97 .label text{fill:#333}#mermaid-svg-F8dvnEDl6rEgSP97 .node rect,#merm…

PullToRefreshListView中嵌套ViewPager滑動沖突的解決

PullToRefreshListView中嵌套ViewPager滑動沖突的解決 最近恰好遇到PullToRefreshListView中需要嵌套ViewPager的情況,ViewPager 作為頭部添加到ListView中&#xff0c;發先ViewPager在滑動過程中流暢性太差幾乎很難左右滑動。在網上也看了很多大神的介紹&#xff0c;看了ViewP…

神經網絡 卷積神經網絡_如何愚弄神經網絡?

神經網絡 卷積神經網絡Imagine you’re in the year 2050 and you’re on your way to work in a self-driving car (probably). Suddenly, you realize your car is cruising at 100KMPH on a busy road after passing through a cross lane and you don’t know why.想象一下…

數據特征分析-分布分析

分布分析用于研究數據的分布特征&#xff0c;常用分析方法&#xff1a; 1、極差 2、頻率分布 3、分組組距及組數 df pd.DataFrame({編碼:[001,002,003,004,005,006,007,008,009,010,011,012,013,014,015],\小區:[A村,B村,C村,D村,E村,A村,B村,C村,D村,E村,A村,B村,C村,D村,E村…

開發工具總結(2)之全面總結Android Studio2.X的填坑指南

前言&#xff1a;好多 Android 開發者都在說Android Studio太坑了&#xff0c;老是出錯&#xff0c;導致開發進度變慢&#xff0c;出錯了又不知道怎么辦&#xff0c;網上去查各種解決方案五花八門&#xff0c;有些可以解決問題&#xff0c;有些就是轉來轉去的寫的很粗糙&#x…

無聊的一天_一人互聯網公司背后的無聊技術

無聊的一天Listen Notes is a podcast search engine and database. The technology behind Listen Notes is actually very very boring. No AI, no deep learning, no blockchain. “Any man who must say I am using AI is not using True AI” :)Listen Notes是一個播客搜索…

如何在Pandas中使用Excel文件

From what I have seen so far, CSV seems to be the most popular format to store data among data scientists. And that’s understandable, it gets the job done and it’s a quite simple format; in Python, even without any library, one can build a simple CSV par…

Js實現div隨鼠標移動的方法

HTML: <div id"odiv" style" COLOR: #666; padding: 2px 8px; FONT-SIZE: 12px; MARGIN-RIGHT: 5px; position: absolute; background: #fff; display: block; border: 1px solid #666; top: 50px; left: 10px;"> Move_Me</div>第一種&…

leetcode 867. 轉置矩陣

給你一個二維整數數組 matrix&#xff0c; 返回 matrix 的 轉置矩陣 。 矩陣的 轉置 是指將矩陣的主對角線翻轉&#xff0c;交換矩陣的行索引與列索引。 示例 1&#xff1a; 輸入&#xff1a;matrix [[1,2,3],[4,5,6],[7,8,9]] 輸出&#xff1a;[[1,4,7],[2,5,8],[3,6,9]] …

數據特征分析-對比分析

對比分析是對兩個互相聯系的指標進行比較。 絕對數比較(相減)&#xff1a;指標在量級上不能差別過大&#xff0c;常用折線圖、柱狀圖 相對數比較(相除)&#xff1a;結構分析、比例分析、空間比較分析、動態對比分析 df pd.DataFrame(np.random.rand(30,2)*1000,columns[A_sale…

Linux基線合規檢查中各文件的作用及配置腳本

1./etc/motd 操作&#xff1a;echo " Authorized users only. All activity may be monitored and reported " > /etc/motd 效果&#xff1a;telnet和ssh登錄后的輸出信息 2. /etc/issue和/etc/issue.net 操作&#xff1a;echo " Authorized users only. All…

tableau使用_使用Tableau升級Kaplan-Meier曲線

tableau使用In a previous article, I showed how we can create the Kaplan-Meier curves using Python. As much as I love Python and writing code, there might be some alternative approaches with their unique set of benefits. Enter Tableau!在上一篇文章中 &#x…

踩坑 net core

webclient 可以替換為 HttpClient 下載獲取url的內容&#xff1a; 證書&#xff1a; https://stackoverflow.com/questions/40014047/add-client-certificate-to-net-core-httpclient 轉載于:https://www.cnblogs.com/zxs-onestar/p/7340386.html

我從參加#PerfMatters會議中學到的東西

by Stacey Tay通過史黛西泰 我從參加#PerfMatters會議中學到的東西 (What I learned from attending the #PerfMatters conference) 從前端的網絡運行情況發布會上的注意事項 (Notes from a front-end web performance conference) This week I had the privilege of attendin…

修改innodb_flush_log_at_trx_commit參數提升insert性能

最近&#xff0c;在一個系統的慢查詢日志里發現有個insert操作很慢&#xff0c;達到秒級&#xff0c;并且是比較簡單的SQL語句&#xff0c;把語句拿出來到mysql中直接執行&#xff0c;速度卻很快。 這種問題一般不是SQL語句本身的問題&#xff0c;而是在具體的應用環境中&#…