Pipelines CI/CD veloci e facili con versione semantica per qualsiasi lingua o strumento. Il rilascio di una nuova versione di uno strumento dovrebbe essere noioso. nessuna cerimonia, nessuna pianificazione di riunioni, nemmeno una discussione. dovrebbe essere trasparente, senza sforzo, affidabile e persino informativo – di più su questo in seguito. Tuttavia, come consulente software che aiuta i team a implementare soluzioni DevOps, trovo spesso che questo non sia il caso. Ciò che trovo varia enormemente in termini di qualità, quindi invece di dirvi cosa non mi piace, concentratiamoci su come mi piace strutturare le mie pipelines al fine di imbarcare nuovi repositori rapidamente e facilmente. Per comprendere la mia prospettiva, vorrei condividere come le mie opinioni sul tema si sono evolute nel corso degli anni. Attualmente, applico un processo che comporta l'organizzazione di "blocchi LEGO" di flussi di lavoro modulari con modifiche minori, come i cambiamenti dei parametri. Idealmente, mi occupo di impostazioni predefinite che mi permettono di semplicemente copiare e incollare gli stessi blocchi da un progetto all'altro quando condividono lo stesso tipo. Ad esempio, il processo di costruzione per la libreria Rust X è probabilmente circa lo stesso della libreria Rust Y, e Node server foo è probabilmente circa lo stesso di Node server bar. Nel corso degli anni ho cercato di assemblare componenti open source per raggiungere questo obiettivo, ma non ho mai trovato la combinazione giusta. Ma prima... Mi rendo conto che la versione e il rilascio non sono i temi più emozionanti; tuttavia, è un problema che ogni progetto affronta, anche quando è codificato (probabilmente soprattutto!). Fare ciò correttamente renderà il tuo progetto molto più professionale e comunicare i cambiamenti ai suoi utenti. Questo stabilisce più fiducia nei tuoi progetti, aiutando gli sviluppatori a comprendere e adottare i nuovi cambiamenti in modo chiaro e coerente. All’inizio... All’inizio della mia carriera nell’ingegneria del software, i rilasci sono stati il sottoprodotto di traguardi, raggiunti attraverso una serie di sprint, pianificati, al meglio delle capacità di tutti, in una serie di riunioni di pianificazione in cui il retrocesso è stato scosso e sono stati scelti i compiti che erano degni. Faremmo del nostro meglio per scrivere una specifica di un piano, e stimare un numero di Fibonacci o la dimensione della maglietta, o nel peggiore dei casi, un numero di giorni. Il rilascio è stato il culmine di questo processo.La consegna di consegnabili, spedito agli utenti reali. Come il culmine di questo processo, e alte scommesse per farlo bene, il rilascio è stato un momento emotivo. di eccitazione? La paura ? Forse alcuni che hai attivato hanno avuto il tuo cuore in gara mentre hanno messo in moto le macchine. C'è anche il dettaglio e il dramma di decidere un numero di versione. Si tratta di una grande versione? una nuova versione?? minore? patch? A volte il marketing ha dettato la versione... 2.0! A questo punto della mia carriera, non era in gran parte la mia opinione che contava su questo argomento di numeri di versione, e guardando indietro, probabilmente non avrebbe dovuto essere di nessuno (vedrete cosa intendo più tardi). Non ero responsabile per i rilasci all’inizio... Tuttavia... ciò non sarebbe durato per sempre. In Open Source A un certo punto della mia carriera, sono diventato interessato a contribuire ad open source. Generalmente, sotto forma di moduli npm, come ero molto in Node in quel momento. Era il mio turno di essere responsabile dei rilasci. Non ricordo come, forse attraverso qualche newsletter o forse parte della riunione NYC NodeJS che Matt Walters e io avevamo usato per correre insieme - ho incontrato la biblioteca. Semantic Release ha implementato un principio, con cui ho vibrato come sviluppatore web, di una separazione delle preoccupazioni basata sulla semantica. semantic-release Prima di uscire e iniziare a usare semantic-release, ci sono alcune limitazioni che ho incontrato con esso... E arriverò a quelle in un attimo. In primo luogo, ad un livello elevato, l'idea di base che semantic-release predicava era che si seguisse un formato specifico per i vostri messaggi di commissione, e in base ai messaggi, la versione poteva essere calcolata. Parlava di rimuovere l'emozione dai rilasci, rendendoli robotici, in base a ciò che è realmente cambiato. Se c'era una nuova versione principale - v2 a v3, per esempio, questo significava che c'era un cambiamento drammatico. Per significare questo nel tuo messaggio di commento, includeresti nel corpo del Comitato. BREAKING CHANGE: feat: revamp user auth flow BREAKING CHANGE: Per Chad's "game-changer" vision in the 3am Slack rant, we've ditched the old auth system for a blockchain-based solution because "passwords are so 2024." Update your clients or enjoy the 500 errors! Le versioni minori, come v2.0.0 a v2.1.0, significavano che c'era una nuova funzionalità aggiunta. feat: add dark mode toggle Per the 47-comment thread in the "urgent" ticket, users can now save their retinas. Dark mode added, but brace for the inevitable "make it darker" feedback. Le versioni di patch hanno segnalato correzioni, o reattori, o fondamentalmente qualsiasi altra cosa che dovrebbe innescare una nuova versione. fix: revert "fix" by AI that skipped the breaking tests to avoid the failure E infine, alcuni impegni non dovrebbero innescare un rilascio affatto. “Chores” come mi sono stati introdotti. No-ops, come li chiamo. chore: update release pipeline version from v3.1.0 to v3.1.1 Questo formato specifico di messaggi di commit era noto come Puoi controllare la loro pagina per le specifiche complete, ma volevo condividere la verità. Commissioni convenzionali Inoltre, queste informazioni contenute nei commits potrebbero anche essere visualizzate come un log di cambiamento, ad esempio evidenziando un cambiamento in fase di rottura. What's new in v2.0.0 * feat: remove deprecated API BREAKING CHANGE: the FooBar API that was deprecated. To upgrade, you can use the new BazBar API. Quindi, per un po ', semantic-release è stato grande per me. Per i progetti Node, è ancora... Tuttavia... di DevOps Sono sempre stato interessato all'idea di come costruire sistemi distribuiti scalabili, quindi è stato qualcosa che ho perseguito per un bel po 'di tempo nella mia carriera. storia lunga breve, alla fine ho imparato come farlo bene, ma ho avuto un nuovo problema: come implementare tutti i pezzi. Questi non erano moduli npm; erano applicazioni, servizi, database e cadenze! Mi è piaciuta la semplicità della rilascio semantico, ma ha funzionato bene solo per i progetti Node.js. Certo, si potrebbe, e ho fatto un paio di volte, aggiungere un file a progetti non nodali, ma che era confuso e hacky nel migliore dei casi. package.json Intorno a questo momento, sono diventato profondamente coinvolto in DevOps, durante l'era di Jenkins, mentre Docker cominciava a guadagnare trazione. Ho imparato a scrivere pipelines con Jenkins e a distribuire tutto con Docker Swarm! Il mio primo viaggio di DevOps e la scoperta di Docker per la distribuzione. Ho anche abbracciato lo sviluppo basato sul trunk in quel momento, e mi sono impegnato a padroneggiare. il mio articolo più recente e ancora rilevante e accurato Guida a Git con Trunk Based Development spiega il perché e come di questo se sei interessato. Anche io avevo a che fare con lo sviluppo basato sul trunk in quel momento, e Il mio più recente e ancora rilevante e accurato L'articolo spiega il perché e come di questo, se siete interessati. Impegnarsi per il Maestro Guida per andare con lo sviluppo basato sul trunk Ho sempre voluto che questi progetti con cui ho lavorato fossero versati e rilasciati come i progetti di rilascio semantico, ma non ho mai trovato una soluzione che funzionasse. Non era la cosa più importante della mia lista, quindi in generale l'ho definita abbastanza buona e ho vissuto con i difetti. Nel corso del tempo, come consulente DevOps, ho incontrato e rilasciato vari progetti in più lingue e framework, e ciascuno ha richiesto la versione, le rilasci e i changelogs. Un altro mal di testa che ho spesso incontrato sono stati i grandi tubi monolitici. Venendo dall'era di Jenkins, lo otto, questo è il modo in cui ho usato per scrivere i tubi anche. Cercherò di avere l'intero flusso di rilascio in una grande serie di fasi, a partire da una spinta al principale. Se si spinge al principale, vari controlli di qualità funzionerebbero e una nuova versione sarebbe costruita, pubblicata, etichettata e rilasciata. Questo non è terribile di per sé e probabilmente anche "sufficientemente buono" nella maggior parte dei casi; tuttavia, come consulente DevOps, devo farlo ripetutamente. Dividere le cose in pezzi più piccoli e più modulari consente a quei pezzi di servire più progetti. , un'idea che deriva dall'adozione delle filosofie UNIX. La copertura delle idee Ad esempio, un pipeline Node Quality può essere lo stesso in ogni progetto Node, supponendo che si seguano le convenzioni standard di script npm, e quindi un pipeline generico per eseguire linting, costruzione e test di unità può essere condiviso nella maggior parte, se non tutti, i progetti Node.js. e così via, e la sezione scrittura della Il file determina cosa succede quando Il comando è in corso. npm run lint --if-present package.json lint Pipelines di alto livello per la versione e il rilascio A un livello elevato, ogni progetto che deve essere rilasciato sarà prima etichettato con un nuovo numero di versione. Ho usato GitHub Actions più spesso, poiché penso che le pipelines siano merci, ed è una cosa semplice da iniziare.Ho usato molte, ma sono tutte essenzialmente le stesse - eseguire una serie di passaggi con un volume condiviso. La versione stessa, se stiamo seguendo lo standard dei compromessi convenzionali legati ad un aumento di versione semantica, non è una cosa specifica per la lingua. Per molto tempo, ho legato le rilasci alle versioni, pensando che fossero parte della stessa cosa, quando in realtà sono due entità distinte unite insieme. Dividendoli separatamente, la parte di versione del pipeline divenne la sua parte modulare, che in seguito innescò la costruzione di quella versione e il successivo rilascio. Per ogni progetto, in GitHub Actions, ho due pipeline: On commit to the trunk branch, version, and tag When a commit occurs in the trunk branch (usually or ), trigger a pipeline that runs quality checks, and, if they pass, calculates a new version number. It then creates and pushes a tag with that new version number. We can also use this opportunity to update that version number in the code base if necessary, and generate a change log from the commit data that was used to calculate the new version number. main master When a tag is created, build new versions and release them. This step is simplified by the previous step of doing the version bump. Everything’s already been bumped to the new version. We can just run build and release using the tag as the base. Come ho detto in precedenza, dopo aver provato molte volte a riunire componenti open source dal GitHub Actions Marketplace, alla fine ho ceduto e ho scritto il mio proprio strumento che gestisce il primo passo. Introduzione vnext Successivo vnext è uno strumento Rust CLI veloce che utilizza i messaggi di commissione convenzionali per calcolare la prossima versione semantica, automatizzando i colpi principali, minori o patch per rilasci semplificati. Ecco come usarlo. NEXT_VERSION=v`vnext` vnext --changelog > CHANGELOG.md Penso che sia piuttosto semplice!Dimmi cosa ne pensi. Si basa interamente sulla storia git del progetto. Non importa quale lingua o strumento stai rilasciando; il processo di versione è fondamentalmente lo stesso. Ottieni una nuova versione, aggiornala in alcuni file, crei un changelog, tag e push. L'unica differenza è quali file devono essere aggiornati - questo è considerato nel flusso di lavoro che condividerò in un momento. è veloce e facile da installare tramite - di Una volta configurato, è possibile eseguire: vnext ubi Il “Universal Binary Installer” ubi --project unbounded-tech/vnext Ho anche creato un flusso di lavoro GitHub Actions condiviso che puoi chiamare, che gestisce tutti quei dettagli. Ecco come utilizzare il workflow condiviso: name: On Push Main, Version and Tag on: push: branches: - main - master permissions: packages: write contents: write jobs: version-and-tag: uses: unbounded-tech/workflow-vnext-tag/.github/workflows/workflow.yaml@v1 with: useDeployKey: true changelog: true La maggior parte dei progetti dovrà anche configurare come e quali file aggiornare con il nuovo numero di versione. Al momento, Sostenere due metodi generici ( e e alcune opzioni linguistiche specifiche. vnext yqPatches regexPatches Le opzioni specifiche per la lingua sono le più semplici da usare. ad esempio, la due usare per aggiornare i file di pacchetto del progetto. with.node true npm Utilizzare lo strumento per patchare campi specifici in un file YAML. spesso uso questo per aggiornare i numeri di versione nei grafici Helm: yqPatches yq version-and-tag: uses: unbounded-tech/workflow-vnext-tag/.github/workflows/workflow.yaml@v1.13.0 secrets: GH_PAT: ${{ secrets.YOUR_ORG_SECRET_PAT }} with: usePAT: true changelog: true yqPatches: | patches: - filePath: helm/values.yaml selector: .image.tag valuePrefix: "v" - filePath: helm/Chart.yaml selector: .version valuePrefix: "v" Ho anche sfruttato questa opportunità per condividere come utilizzare un Token di accesso personale invece di una chiave di installazione. Ho anche sfruttato questa opportunità per condividere come utilizzare un Token di accesso personale invece di una chiave di installazione. usare per trovare e sostituire una stringa con il nuovo numero di versione inserito. regexPatches sed regexPatches: | patches: - filePath: package/composition.yaml regex: /ghcr.io/org-name/package-name:(.*)/g valuePrefix: ghcr.io/org-name/package-name:v - filePath: README.md regex: /Current version: v[0-9]+\.[0-9]+\.[0-9]+/g valuePrefix: Current version: v Puoi anche usare una combinazione di opzioni. Una nuance sulle azioni di GitHub Quando si esegue un'azione su GitHub Actions, per impostazione predefinita, l'operatore genera un token di autenticazione temporanea GitHub. Questo token ha il permesso di eseguire alcune attività di base; tuttavia, non è mai permesso di attivare altri pipelines. Ma il nostro prossimo passo dopo aver etichettato una nuova versione è stato quello di attivare un altro pipeline con quel tag! Non preoccuparti, questo è progettato - semplicemente una misura di GitHub per prevenire il girare involontariamente un sacco di corridori. Ci sono diversi modi per essere intenzionale su di esso - ho già mostrato un esempio di due: Utilizzo di una chiave di distribuzione e delle corrispondenti azioni GitHub Secret Utilizzare un token di accesso personale come segreto delle azioni di GitHub Creare un'applicazione GitHub (teoricamente - non ho avuto bisogno di questa opzione) L'uso di un Token di accesso personale è conveniente se sei un cliente a pagamento nell'ecosistema GitHub, poiché i segreti di tutta l'organizzazione sono disponibili. Sul livello gratuito, questa non è un'opzione, quindi ti mostrerò come impostare una chiave di distribuzione. In realtà, l'ho reso molto semplice costruendolo nella CLI. È una grande opzione, poiché quando configurato in questo modo, nessun essere umano ha bisogno di conoscerlo, e può essere facilmente ruotato ricaricando lo stesso comando. vnext Per ogni repository che si desidera impostare per rilasciare con una chiave di distribuzione, nel directory del progetto... vnext In primo luogo, ottenere un token auth utilizzando Con il permesso di gestire le chiavi: gh gh auth refresh -h github.com -s admin:public_key -s admin:ssh_signing_key export GITHUB_TOKEN=$(gh auth token) E poi correre: vnext generate-deploy-key Potresti chiedersi, questo non può entrare in una pipeline da solo? Purtroppo, non riesco a trovare un modo per automatizzare questo passaggio in Github Actions senza creare un Token di accesso personale, poiché il token predefinito non può modificare i segreti. Questo sconfigge la pupose di utilizzare una chiave di distribuzione invece nel livello libero, poiché dovresti crearlo in ogni repo. Questo richiede una sorta di gestione segreta per renderlo facile, e quindi lo rende più funzionale rispetto all'uso di una chiave di distribuzione. Potresti chiedersi, questo non può entrare in una pipeline da solo? Purtroppo, non riesco a trovare un modo per automatizzare questo passaggio in Github Actions senza creare un Token di accesso personale, poiché il token predefinito non può modificare i segreti. Questo sconfigge la pupose di utilizzare una chiave di distribuzione invece nel livello libero, poiché dovresti crearlo in ogni repo. Questo richiede una sorta di gestione segreta per renderlo facile, e quindi lo rende più funzionale rispetto all'uso di una chiave di distribuzione. Con il tuo Deploy Key, o Personal Access Token (PAT), in atto, e il flusso di lavoro di versione e tag in esecuzione spinge al tuo ramo trunk, il passo successivo è quello di rilasciare! Questo varierà per progetto, ma sono tutti attivati dalla versione contrassegnata dal passaggio precedente. name: On Version Tag, Trigger GitHub Release on: push: tags: - 'v*.*.*' permissions: contents: write jobs: release: uses: unbounded-tech/workflow-simple-release/.github/workflows/workflow.yaml@v1 with: tag: ${{ github.ref_name }} name: ${{ github.ref_name }} O, se fosse un progetto Rust, forse qualcosa del genere: name: On Version Tagged, Build and Publish Rust Binaries on: push: tags: - "v*.*.*" permissions: contents: write jobs: build-and-release: uses: unbounded-tech/workflows-rust/.github/workflows/release.yaml@v1 with: binary_name: ${{ github.event.repository.name }} build_args: "--release --features vendored" O se fosse un'applicazione con Dockerfile, e k8s definizioni di risorse per le distribuzioni di Gitops, forse qualcosa di simile a questo: name: promote on: push: tags: - v*.*.* permissions: contents: write packages: write issues: write pull-requests: write jobs: publish: uses: unbounded-tech/workflows-containers/.github/workflows/publish.yaml@v1.1.1 release: needs: publish uses: unbounded-tech/workflow-simple-release/.github/workflows/workflow.yaml@v1 with: tag: ${{ github.ref_name }} name: ${{ github.ref_name }} promote: needs: release uses: unbounded-tech/workflows-gitops/.github/workflows/helm-promote.yaml@v1 secrets: GH_PAT: ${{ secrets.GH_PAT }} with: environment_repository: your-org/staging-env path: .gitops/deploy project: staging Nota: Una chiave di distribuzione non può spingere ad altri repos, come nel passaggio di promozione dei gitops, quindi potresti prendere in considerazione l'uso di un PAT ovunque per questo repository. Se hai un sacco di carichi di lavoro come questo, l'aggiornamento a un org a pagamento potrebbe valere la pena per i segreti ampie dell'organizzazione piuttosto che configurare ogni repo separatamente. Nota: Una chiave di distribuzione non può spingere ad altri repos, come nel passaggio di promozione dei gitops, quindi potresti prendere in considerazione l'uso di un PAT ovunque per questo repository. Se hai un sacco di carichi di lavoro come questo, l'aggiornamento a un org a pagamento potrebbe valere la pena per i segreti ampie dell'organizzazione piuttosto che configurare ogni repo separatamente. In generale, ogni rilascio è una combinazione di alcuni pezzi di questi moduli simili, che fanno quasi le stesse cose ma per i loro strumenti o linguaggi specifici. Di solito, le organizzazioni almeno cercano di seguire molti degli stessi modelli tra le applicazioni e i servizi che costruiscono, e quindi la rottura dei flussi di lavoro in pezzi modulari condivisi consente ai sviluppatori di copiare e incollare il loro sapore di queste chiamate di flusso di lavoro condivise a ogni progetto di questo tipo. Pubblicazioni coerenti con Changelogs Potresti aver notato una sorta di sguardo sul Il changelog è come comunicare i modi in cui il tuo progetto è cambiato ad altri sviluppatori. with.changelog Oltre alle versioni scintillanti, usa anche i messaggi di commissione per costruire questo changelog e lo salva in un file chiamato CHANGELOG.md, che viene commesso insieme al tag di versione e ai colpi di versione. vnext Nascosto in quei flussi di lavoro di rilascio che ho condiviso sopra, questo file viene utilizzato come il corpo della rilascia GitHub. Il progetto stesso: vnext Questo rilascio era una versione patch, poiché conteneva una correzione, sotto forma di una versione di dipendenza, e una serie di altri lavori. Queste note di rilascio vengono poi visualizzate in altri strumenti, come , uno strumento che rende PR per mantenere aggiornate le tue dipendenze. Rinnovazione Quando si fondono le richieste di pull, mi piace usare la funzione Squash e Merge di GitHub al fine di avere l'opportunità di scrivere un bel titolo e il corpo del messaggio di commit finale che verrà utilizzato nel changelog. Ad esempio: Come mostrato nell'esempio, è possibile impostare un Markdown completo come corpo di commissione. Esso verrà riprodotto correttamente nelle note di rilascio! Conclusione So che la versione e il rilascio non sono il tema più sexy; è piuttosto noioso - o meglio, dovrebbe essere! Ma non è sempre così, è per questo che ho creato E un mucchio di Ora, posso facilmente imbarcare la maggior parte dei progetti molto rapidamente! vnext Flussi di lavoro condivisi Speriamo sia utile anche a voi! Vi prego di farmi sapere se darete e alcuni flussi di lavoro condivisi un tentativo! apprezzerò alcune stelle su GitHub e una condivisione se li trovi utili! vnext