<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Vivien Ogoun</title>
    <description>The latest articles on DEV Community by Vivien Ogoun (@vivien_ogoun).</description>
    <link>https://dev.to/vivien_ogoun</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2964672%2Fe3c5f017-8b76-42ea-a919-b7dcfd144769.png</url>
      <title>DEV Community: Vivien Ogoun</title>
      <link>https://dev.to/vivien_ogoun</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/vivien_ogoun"/>
    <language>en</language>
    <item>
      <title>From Pull Request to Preview: Automating Cloud Deployments with Pulumi + GitHub</title>
      <dc:creator>Vivien Ogoun</dc:creator>
      <pubDate>Mon, 07 Apr 2025 06:59:20 +0000</pubDate>
      <link>https://dev.to/vivien_ogoun/from-pr-to-preview-automating-cloud-deployments-with-pulumi-github-4fdh</link>
      <guid>https://dev.to/vivien_ogoun/from-pr-to-preview-automating-cloud-deployments-with-pulumi-github-4fdh</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/pulumi"&gt;Pulumi Deploy and Document Challenge&lt;/a&gt;: Get Creative with Pulumi and GitHub&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;I created &lt;strong&gt;Pulumi Preview Environment Deployer&lt;/strong&gt;, a Node.js-based tool that automatically deploys preview environments to AWS S3 when a pull request is opened, and tears them down when the PR is closed. It uses &lt;strong&gt;Pulumi's Automation API&lt;/strong&gt; to provide an efficient and isolated testing environment for every PR.&lt;/p&gt;

&lt;h2&gt;
  
  
  How It Works
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;A webhook listener receives GitHub PR events.&lt;/li&gt;
&lt;li&gt;On PR open, Pulumi deploys a static website using the PR number as the stack name.&lt;/li&gt;
&lt;li&gt;On PR close, the stack is destroyed.&lt;/li&gt;
&lt;li&gt;Each preview environment is isolated by PR.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Pull request opened (or reopened) on github
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fex2k89of31dlcypjrs0u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fex2k89of31dlcypjrs0u.png" alt="Screenshot of open pull request"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Event received by the nodejs server
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6ztkbsk9685p6181so8i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6ztkbsk9685p6181so8i.png" alt="Screenshot of event received by the nodejs server"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Preview deployment start automatically for the PR
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvga5j8hu9xz5ql949li5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvga5j8hu9xz5ql949li5.png" alt="Screenshot of starting preview deployment for the PR"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Preview deployment finish and output preview site url
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F350ww9x4wd5aiir74p3q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F350ww9x4wd5aiir74p3q.png" alt="Screenshot of preview deployment finish and output preview site url"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Preview deployment accessible in the browser
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpb18s3p4ipd57kg06kyj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpb18s3p4ipd57kg06kyj.png" alt="Screenshot of preview deployment accessible in the browser"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The deployed preview environments are tied to active pull requests and hosted on AWS S3. You can see a typical deployed preview site using a link like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://&amp;lt;unique-bucket&amp;gt;.s3-website-us-east-1.amazonaws.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;You can test it yourself by following the project repo README, opening a PR on your repo and watching the magic happen!&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Project Repo
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/vivienogoun" rel="noopener noreferrer"&gt;
        vivienogoun
      &lt;/a&gt; / &lt;a href="https://github.com/vivienogoun/pulumi-preview-deployer" rel="noopener noreferrer"&gt;
        pulumi-preview-deployer
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Deploy preview environments for PRs using Pulumi and GitHub
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Pulumi Preview Environment Deployer 🚀&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;This project automatically deploys &lt;strong&gt;preview environments&lt;/strong&gt; to AWS S3 when a pull request is opened, and &lt;strong&gt;destroys them&lt;/strong&gt; when the PR is closed — all using Pulumi's Automation API and GitHub webhooks.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;✨ Features&lt;/h2&gt;
&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Automatic deployment on PR open&lt;/li&gt;
&lt;li&gt;Auto-destroy on PR close&lt;/li&gt;
&lt;li&gt;Uses Pulumi's Automation API with Node.js&lt;/li&gt;
&lt;li&gt;Static site hosted via AWS S3&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;📸 Demo&lt;/h2&gt;
&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Pull request opened (or reopened) on github&lt;/h3&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/vivienogoun/pulumi-preview-deployer/./demo/pulumi-demo-1.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fvivienogoun%2Fpulumi-preview-deployer%2F.%2Fdemo%2Fpulumi-demo-1.png" alt="Screenshot of open pull request"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Event received by the nodejs server&lt;/h3&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/vivienogoun/pulumi-preview-deployer/./demo/pulumi-demo-2.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fvivienogoun%2Fpulumi-preview-deployer%2F.%2Fdemo%2Fpulumi-demo-2.png" alt="Screenshot of event received by the nodejs server"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Preview deployment start automatically for the PR&lt;/h3&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/vivienogoun/pulumi-preview-deployer/./demo/pulumi-demo-3.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fvivienogoun%2Fpulumi-preview-deployer%2F.%2Fdemo%2Fpulumi-demo-3.png" alt="Screenshot of starting preview deployment for the PR"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Preview deployment finish and output preview site url&lt;/h3&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/vivienogoun/pulumi-preview-deployer/./demo/pulumi-demo-4.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fvivienogoun%2Fpulumi-preview-deployer%2F.%2Fdemo%2Fpulumi-demo-4.png" alt="Screenshot of preview deployment finish and output preview site url"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Preview deployment accessible in the browser&lt;/h3&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/vivienogoun/pulumi-preview-deployer/./demo/pulumi-demo-5.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fvivienogoun%2Fpulumi-preview-deployer%2F.%2Fdemo%2Fpulumi-demo-5.png" alt="Screenshot of preview deployment accessible in the browser"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;🛠 Tech Stack&lt;/h2&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Pulumi (TypeScript)&lt;/li&gt;
&lt;li&gt;Node.js (Express + Automation API)&lt;/li&gt;
&lt;li&gt;AWS S3&lt;/li&gt;
&lt;li&gt;GitHub Webhooks&lt;/li&gt;
&lt;li&gt;ngrok (for local testing)&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;🚀 How It Works&lt;/h2&gt;

&lt;/div&gt;


&lt;ol&gt;

&lt;li&gt;A webhook listener receives GitHub PR events.&lt;/li&gt;

&lt;li&gt;On PR open, Pulumi deploys a static website using the PR number as the stack name.&lt;/li&gt;

&lt;li&gt;On PR close, the stack is destroyed.&lt;/li&gt;

&lt;li&gt;Each preview…&lt;/li&gt;

&lt;/ol&gt;
&lt;/div&gt;
&lt;br&gt;
  &lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/vivienogoun/pulumi-preview-deployer" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;h2&gt;
  
  
  My Journey
&lt;/h2&gt;

&lt;p&gt;This project was both challenging and rewarding. I started by designing a simple static site deployment to AWS using Pulumi. I ran into issues with S3 public access settings (block public ACLs and policies), which required multiple iterations and research into the correct use of &lt;code&gt;BucketV2&lt;/code&gt;, &lt;code&gt;BucketPublicAccessBlock&lt;/code&gt;, and ownership settings.&lt;/p&gt;

&lt;p&gt;The real fun began with integrating Pulumi’s Automation API. I learned how to manage stacks programmatically, respond to PR events in real time, and tie everything together using GitHub webhooks and an Express server.&lt;/p&gt;

&lt;p&gt;What stood out most was how &lt;strong&gt;flexible Pulumi is&lt;/strong&gt;, letting me script infrastructure logic just like any other application code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using Pulumi with GitHub
&lt;/h2&gt;

&lt;p&gt;I used:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pulumi Automation API&lt;/strong&gt; (in Node.js) to deploy and destroy stacks on demand&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pulumi AWS provider&lt;/strong&gt; to deploy the static site to S3&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub Webhooks&lt;/strong&gt; to trigger Pulumi workflows on PR events&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The ability to programmatically manage stacks and resources via code is a game-changer — I didn’t have to rely on GitHub Actions or manual &lt;code&gt;pulumi up/down&lt;/code&gt; commands. It’s all automatic and runs locally during development.&lt;/p&gt;

&lt;p&gt;I didn’t use Pulumi Copilot this time, but I’m excited to try it for future use cases.&lt;/p&gt;

&lt;p&gt;Thanks for reading and big thanks to Pulumi + DEV for hosting this challenge 🚀&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>pulumichallenge</category>
      <category>github</category>
      <category>api</category>
    </item>
    <item>
      <title>Exploring KendoReact by building a Gmail web clone</title>
      <dc:creator>Vivien Ogoun</dc:creator>
      <pubDate>Mon, 24 Mar 2025 07:06:26 +0000</pubDate>
      <link>https://dev.to/vivien_ogoun/exploring-kendoreact-by-building-a-gmail-web-clone-2nl3</link>
      <guid>https://dev.to/vivien_ogoun/exploring-kendoreact-by-building-a-gmail-web-clone-2nl3</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/kendoreact"&gt;KendoReact Free Components Challenge&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;I developed a project that replicates the user interface (UI) of Gmail using React and KendoReact components. This focuses solely on mirroring Gmail's visual design elements, such as layout, color schemes, typography, and iconography, to provide users with a familiar and intuitive interface. The project does not incorporate Gmail's functional features like email composition, sending, or receiving.​&lt;/p&gt;

&lt;p&gt;This project demonstrate the versatility of KendoReact in recreating complex, real-world interfaces.&lt;/p&gt;

&lt;h3&gt;
  
  
  Demo
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://kendo-react-gmail-clone.vercel.app/" rel="noopener noreferrer"&gt;Link to app&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuycbdcsmi6m52y42cl4u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuycbdcsmi6m52y42cl4u.png" alt="Image description" width="800" height="404"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/vivienogoun/kendo-react-gmail-clone" rel="noopener noreferrer"&gt;Github repo&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  KendoReact Experience
&lt;/h2&gt;

&lt;p&gt;In developing the Gmail UI clone, I leveraged several KendoReact components to accurately replicate Gmail's interface:​&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;AppBar: Used to create the top navigation bar, providing a consistent and responsive header across the application. ​&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Drawer: Implemented for the left-side navigation panel, allowing users to access different mail categories and labels seamlessly.​&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;ListBox: Employed to display the list of emails, enabling selection and interaction with individual email items. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Window: Utilized to replicate the email composition experience. This component enabled the creation of a window, closely mirroring Gmail's compose email functionality&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Button: Utilized for various actions such as composing a new email, with options to include textual content, predefined icons, or custom elements. ​&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;TextBox: Used in the compose email window to allow users to enter inputs. ​&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Tooltip: Added to provide additional information when users hover over specific UI elements, enhancing usability. ​&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Avatar: Displayed user profile picture in the AppBar, contributing to a more personalized and recognizable interface.​&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;SVG Icons: Integrated in the left-side navigation panel, ensuring a visually consistent experience.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By integrating these KendoReact components, I was able to efficiently recreate Gmail's user interface, ensuring responsiveness and a professional appearance.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>kendoreactchallenge</category>
      <category>react</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
