<?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: jellyfith</title>
    <description>The latest articles on DEV Community by jellyfith (@jellyfith).</description>
    <link>https://dev.to/jellyfith</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%2F2606383%2F95fa57c6-e786-4d60-9d67-4cc0cfd36acb.jpeg</url>
      <title>DEV Community: jellyfith</title>
      <link>https://dev.to/jellyfith</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jellyfith"/>
    <language>en</language>
    <item>
      <title>Monorepo Versioning: Stop the Chaos</title>
      <dc:creator>jellyfith</dc:creator>
      <pubDate>Mon, 02 Jun 2025 18:42:07 +0000</pubDate>
      <link>https://dev.to/jellyfith/monorepo-versioning-stop-the-chaos-3oij</link>
      <guid>https://dev.to/jellyfith/monorepo-versioning-stop-the-chaos-3oij</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;The Git Juggling Act: How to Gracefully Support Legacy &amp;amp; New Major Versions in Your Monorepo&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Inevitable Fork in the Road
&lt;/h3&gt;

&lt;p&gt;You've done it. You launched your shiny 2.x.x version. Months of work, through CI/CD, and then:&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%2Fldncnprgbsqw5rz82sqr.gif" 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%2Fldncnprgbsqw5rz82sqr.gif" alt="Doctor Victor Frankenstein yells " width="1024" height="1024"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It's published.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;But reality quickly sets in. A significant portion of your users are still on 1.x.x. They have their reasons: legacy integrations, "if it ain't broke" mantras, or simply phased rollouts. The truth is, you still need to support both. A critical 1.x.x bug emerges. A non-breaking feature is requested for both versions.&lt;/p&gt;

&lt;p&gt;How do you manage two diverging product lines within a single monorepo? This is a common challenge for growing products. This guide provides a sustainable strategy to keep both your legacy users and your forward momentum on track.&lt;/p&gt;




&lt;h3&gt;
  
  
  The Bedrock: Principles for Peaceful Coexistence
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;First of all&lt;/strong&gt;, this message is for those of us who adhere to a few important source control principles. If we can't agree on the following, this might not be the message for you:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Strict Semantic Versioning (SemVer):&lt;/strong&gt; This is non-negotiable. Your 1.x.x vs. 2.x.x releases must have clear meaning.

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Breaking changes&lt;/strong&gt; = major bumps (2.x.x).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;New features&lt;/strong&gt; = minor bumps (1.1.0, 1.2.0).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bug fixes&lt;/strong&gt; = patch bumps (1.0.1, 1.0.2).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Clear Branching Strategy:&lt;/strong&gt; Define distinct lanes for different types of work. Consistency is paramount to avoid chaos.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automation is Key:&lt;/strong&gt; At scale, manual steps lead to errors. Embrace &lt;strong&gt;CI/CD pipelines&lt;/strong&gt; for builds, tests, releases, and propagation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transparent Communication:&lt;/strong&gt; Inform users about &lt;strong&gt;version lifecycles&lt;/strong&gt;, 1.x.x support timelines, and &lt;strong&gt;migration paths&lt;/strong&gt; to 2.x.x.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  The Juggling Mechanics: Your Git Branching Playbook
&lt;/h3&gt;

&lt;p&gt;For a monorepo supporting distinct major versions, a dedicated release branch for each actively supported major version is essential.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Main Stage: &lt;code&gt;main&lt;/code&gt; (or &lt;code&gt;trunk&lt;/code&gt;)&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;This is the home for &lt;strong&gt;2.x.x&lt;/strong&gt; development. All new, potentially breaking features, architectural shifts, and forward-looking innovations land here. This branch represents your product's future.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;The Legacy Lane: &lt;code&gt;release/1.x.x&lt;/code&gt; (or &lt;code&gt;v1&lt;/code&gt;)&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;This is a long-lived, dedicated branch for the &lt;strong&gt;1.x.x&lt;/strong&gt; line.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Purpose:&lt;/strong&gt; It's for critical bug fixes, security patches, and &lt;strong&gt;non-breaking new features&lt;/strong&gt; that enhance but don't disrupt existing 1.x.x functionality.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Releases:&lt;/strong&gt; Urgent 1.x.x patches originate here (e.g., &lt;code&gt;1.0.x&lt;/code&gt; release). Non-breaking features lead to &lt;code&gt;1.x.0&lt;/code&gt; releases. Changes here apply &lt;em&gt;only&lt;/em&gt; to the 1.x.x world unless propagated.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;h3&gt;
  
  
  Your Standard Workflow: How Features &amp;amp; Fixes Flow
&lt;/h3&gt;

&lt;p&gt;Here are the predictable scenarios:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Scenario 1: New Feature (Only for 2.x.x)&lt;/strong&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Branch:&lt;/strong&gt; Create a new feature branch from &lt;code&gt;main&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Develop:&lt;/strong&gt; Implement the feature leveraging 2.x.x capabilities.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test:&lt;/strong&gt; Write and run tests tailored for the 2.x.x environment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Merge:&lt;/strong&gt; Open a Pull Request (PR) to &lt;code&gt;main&lt;/code&gt;, get approvals, and merge.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scenario 2: Bug Fix (Only for 1.x.x)&lt;/strong&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Branch:&lt;/strong&gt; Create a hotfix branch from &lt;code&gt;release/1.x.x&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fix:&lt;/strong&gt; Implement the bug fix, ensuring no 2.x.x-specific code is introduced.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test:&lt;/strong&gt; Run tests for the 1.x.x environment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Merge:&lt;/strong&gt; Open a PR to &lt;code&gt;release/1.x.x&lt;/code&gt;, get it reviewed, and merge. This leads to a new 1.x.x patch release.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  The Dual-Version Dilemma: Feature/Fix for &lt;em&gt;Both&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;A common challenge is when a non-breaking feature or critical fix needs to be applied to &lt;em&gt;both&lt;/em&gt; 1.x.x and 2.x.x. The core principle:&lt;br&gt;
&lt;strong&gt;Develop the change on the &lt;em&gt;oldest&lt;/em&gt; relevant branch &lt;em&gt;first&lt;/em&gt;, then propagate it forward.&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;❓ &lt;strong&gt;Why?&lt;/strong&gt;
&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Starting on &lt;code&gt;release/1.x.x&lt;/code&gt; forces backward compatibility. It's easier to integrate &lt;em&gt;older&lt;/em&gt;, &lt;em&gt;simpler&lt;/em&gt; changes into a &lt;em&gt;newer&lt;/em&gt;, more &lt;em&gt;complex&lt;/em&gt; codebase than vice-versa. &lt;strong&gt;TLDR&lt;/strong&gt;: Cherry-picking "backward" is prone to conflicts.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Here's the step-by-step workflow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Branch off &lt;code&gt;release/1.x.x&lt;/code&gt;:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;git checkout release/1.x.x
git pull origin release/1.x.x &lt;span class="c"&gt;# Get latest&lt;/span&gt;
git checkout &lt;span class="nt"&gt;-b&lt;/span&gt; feature/dual-purpose-change
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Develop &amp;amp; Test for 1.x.x:&lt;br&gt;&lt;br&gt;
Implement the change, ensuring it adheres to 1.x.x constraints. Thoroughly test in the 1.x.x environment.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Commit &amp;amp; Merge to &lt;code&gt;release/1.x.x&lt;/code&gt;:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;git add &lt;span class="nb"&gt;.&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"feat(my-module): Add dual-purpose feature (for 1.x.x and 2.x.x)"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;Push, open a &lt;strong&gt;Pull Request (PR)&lt;/strong&gt; targeting &lt;code&gt;release/1.x.x&lt;/code&gt;, get approvals, and merge.&lt;/p&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Cherry-Pick to main:&lt;br&gt;
Once merged into release/1.x.x, get the commit hash(es).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Switch to &lt;code&gt;main&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;git checkout main
git pull origin main &lt;span class="c"&gt;# Get latest&lt;/span&gt;
git cherry-pick &amp;lt;commit-hash-from-1.x.x&amp;gt;
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- **Address Conflicts:** `main` may have diverged. Resolve any conflicts manually, adapting the 1.x.x code to fit the 2.x.x architecture.
    - After resolving, `git add .` and `git cherry-pick --continue`.
- **Test on `main` (Essential):** Even if it passed on 1.x.x, **test rigorously** in the 2.x.x environment.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Push to main:&lt;br&gt;
Once verified on main, push your changes (or open a PR for final review).&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git push origin main
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;💡 &lt;strong&gt;When Re-Implementation is Necessary&lt;/strong&gt;
&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Sometimes, the divergence between &lt;code&gt;release/1.x.x&lt;/code&gt; and &lt;code&gt;main&lt;/code&gt; is too great. If a feature's underlying architecture has been completely reworked in 2.x.x, a cherry-pick might be a fool's errand, leading to endless conflicts and a Frankenstein's monster of code. In those rare but real cases, a careful &lt;em&gt;re-implementation&lt;/em&gt; of the feature from scratch on &lt;code&gt;main&lt;/code&gt; is the more pragmatic (though more time-consuming) path. It ensures the feature is truly "native" to 2.x.x.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h3&gt;
  
  
  Beyond the Branches: Scaling Your Sanity
&lt;/h3&gt;

&lt;p&gt;Managing multiple major versions at scale in a monorepo requires robust support systems.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;CI/CD Magic:&lt;/strong&gt; Implement distinct, robust &lt;strong&gt;CI/CD pipelines&lt;/strong&gt; for both &lt;code&gt;release/1.x.x&lt;/code&gt; and &lt;code&gt;main&lt;/code&gt;. Automate linting, static analysis, comprehensive testing (unit, integration, E2E), builds, versioning, and deployments.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Feature Flags:&lt;/strong&gt; For strategic feature rollouts, &lt;strong&gt;feature flags&lt;/strong&gt; allow you to deploy code to both versions (a "dark launch") and enable it independently. This reduces deployment risk and provides granular control.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitoring &amp;amp; Telemetry:&lt;/strong&gt; Implement robust &lt;strong&gt;monitoring&lt;/strong&gt; for both versions in production. Quickly identify issues unique to 1.x.x and track user adoption of 2.x.x.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Documentation:&lt;/strong&gt; Maintain clear, up-to-date documentation on your branching strategy, release process, and guidelines for changes affecting multiple versions.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Conclusion: Embrace the Versioning Dance
&lt;/h3&gt;

&lt;p&gt;Maintaining multiple major versions in a monorepo can seem daunting, but with a clear strategy, disciplined execution, and automation, it becomes a manageable process. This guide provides a blueprint for navigating these complexities with confidence and less stress.&lt;/p&gt;

&lt;p&gt;Remember, you're not just managing code; you're ensuring a smooth, reliable experience for all users.&lt;/p&gt;




</description>
      <category>git</category>
      <category>programming</category>
      <category>product</category>
      <category>designpatterns</category>
    </item>
    <item>
      <title>How to Run Models Locally: A Step-by-Step Guide for Non-Techies</title>
      <dc:creator>jellyfith</dc:creator>
      <pubDate>Mon, 10 Feb 2025 21:11:20 +0000</pubDate>
      <link>https://dev.to/jellyfith/how-to-run-models-locally-a-step-by-step-guide-for-non-techies-2moe</link>
      <guid>https://dev.to/jellyfith/how-to-run-models-locally-a-step-by-step-guide-for-non-techies-2moe</guid>
      <description>&lt;p&gt;Have you ever wondered if there’s a way to experience the power of AI without exposing your data or losing control over what happens at work? Thanks to years of development, running AI models locally on your machine has become not only possible but also increasingly convenient. This guide will show you how to set up and use an offline local language model (LLM), giving you the flexibility to explore AI's capabilities &lt;em&gt;without compromising your privacy&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Download Ollama
&lt;/h2&gt;

&lt;p&gt;First things first—download and install Ollama. It’s a free tool that lets you run AI models locally on your machine. Here’s how:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to the &lt;a href="https://ollama.com/download" rel="noopener noreferrer"&gt;Ollama website&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Choose your operating system (Windows, macOS, or Linux) and download the installer.&lt;/li&gt;
&lt;li&gt;Once downloaded, run the installer.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That’s it! Ollama is now installed on your machine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Verify Ollama is Running
&lt;/h2&gt;

&lt;p&gt;Before we jump into running a model, we need to make sure Ollama is running. This is dead-simple but will require us to open up the terminal. If you're on Windows and are unsure which terminal to use, you can just open Command Prompt and use that. Once you're in the terminal, just type the following to verify Ollama is running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ollama
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Press &lt;code&gt;Enter&lt;/code&gt; and you should see some info pop up about how to use ollama on the command line. If that doesn't happen and you get output that says something like "&lt;strong&gt;command not defined&lt;/strong&gt;," you may need to try running it again or double-checking that it downloaded.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Choose a Model
&lt;/h2&gt;

&lt;p&gt;Now that Ollama is running, it’s time to pick a model! There are thousands of pre-trained models available directly through Ollama. Here are a few popular options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://ollama.com/library/deepseek-r1" rel="noopener noreferrer"&gt;&lt;strong&gt;deepseek-r1&lt;/strong&gt;&lt;/a&gt;: A versatile model for various tasks.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ollama.com/library/llama3.2" rel="noopener noreferrer"&gt;&lt;strong&gt;llama3.2&lt;/strong&gt;&lt;/a&gt; - Great for text chat and code generation.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ollama.com/library/mistral:instruct" rel="noopener noreferrer"&gt;&lt;strong&gt;mistral:instruct&lt;/strong&gt;&lt;/a&gt; - Fine-tuned for conversational contexts (my personal favorite).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you’re not sure which one to choose, start with a lighter-weight model (like 1B parameters) and go with something multi-purpose like llama3.2.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Download and Run your Model
&lt;/h2&gt;

&lt;p&gt;Pulling and running your model used to be multiple steps, but now all you should need to do is this to download and run it in one go:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ollama run deepseek-r1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(Remove &lt;code&gt;deepseek-r1&lt;/code&gt; if you picked a different model.)&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Done!
&lt;/h2&gt;

&lt;p&gt;Wait for the installation script to finish, and voilà—you are now chatting with your very own local AI language model. You can start using it immediately.&lt;/p&gt;

&lt;h2&gt;
  
  
  Optional: Use Integrated Tools
&lt;/h2&gt;

&lt;p&gt;If you want to use AI within your applications, you may want to checkout some great local LLM integrations for IDEs, note-taking apps, etc. There are tons of tools that work out-of-the-box with Ollama which make working with localized models even easier:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://msty.app/" rel="noopener noreferrer"&gt;&lt;strong&gt;Msty&lt;/strong&gt;&lt;/a&gt; - A free chat app built specifically for Ollama users.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.continue.dev/" rel="noopener noreferrer"&gt;&lt;strong&gt;Continue.dev&lt;/strong&gt;&lt;/a&gt; - A powerful alternative to GitHub Copilot.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://openwebui.com/" rel="noopener noreferrer"&gt;&lt;strong&gt;Open WebUI&lt;/strong&gt;&lt;/a&gt; - A self-hosted interface similar to ChatGPT.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These tools require no extra setup and work right out of the box with your local model.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>deepseek</category>
      <category>security</category>
    </item>
    <item>
      <title>Simplify Browser Extension Deployment with GitHub Actions</title>
      <dc:creator>jellyfith</dc:creator>
      <pubDate>Sat, 01 Feb 2025 17:19:41 +0000</pubDate>
      <link>https://dev.to/jellyfith/simplify-browser-extension-deployment-with-github-actions-37ob</link>
      <guid>https://dev.to/jellyfith/simplify-browser-extension-deployment-with-github-actions-37ob</guid>
      <description>&lt;p&gt;Are you ready to streamline your browser extension deployment process? Manually deploying extensions across multiple stores and managing complex manifest v3 requirements can be a daunting task. With GitHub Actions, you can automate the entire deployment process, ensuring consistency, reducing errors, and saving valuable time.&lt;/p&gt;

&lt;p&gt;In this guide, we’ll walk you through how to automate deployments for Chrome Web Store, Microsoft Edge Add-ons, and Firefox Add-ons using GitHub Actions. Whether you’re deploying individual versions or compiling a release tag, our workflow will handle everything from checking out the latest code to packaging and publishing your extensions.&lt;/p&gt;

&lt;p&gt;By the end of this article, you’ll be able to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Automate deployments across multiple stores&lt;/li&gt;
&lt;li&gt;Manage complex manifest requirements efficiently&lt;/li&gt;
&lt;li&gt;Set up version control integration for smooth deployment&lt;/li&gt;
&lt;li&gt;Take advantage of GitHub’s built-in features like release tracking&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This guide is perfect for developers who want to ensure their extension deploys seamlessly and reliably. So, are you ready to take your extension deployment process to the next level? Let’s get started!&lt;/p&gt;

&lt;h2&gt;
  
  
  The Struggles of Multi-Browser Extension Deployment
&lt;/h2&gt;

&lt;p&gt;Deploying a web extension to various browser web stores can be a laborious and error-prone task, particularly when working with manifest v3. Each platform imposes unique requirements that complicate the deployment process. Here are some common pain points:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Firefox&lt;/strong&gt;: Extensions utilizing bundlers like &lt;a href="https://webpack.js.org/" rel="noopener noreferrer"&gt;webpack&lt;/a&gt; or &lt;a href="https://extension.js.org/docs" rel="noopener noreferrer"&gt;Extension.js&lt;/a&gt; require zipped source code. Additionally, Firefox mandates submissions in Cross-Platform Install (XPI) format.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chrome and Edge&lt;/strong&gt; expect submissions in &lt;code&gt;.zip&lt;/code&gt; format without the need for source code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In addition to these specific requirements, you must manually visit each web store and upload extension artifacts. To ease this burden, we can create a streamlined solution using GitHub Actions. This method will offer us numerous advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Automation&lt;/strong&gt;: The entire deployment pipeline is automated, checking out the project, building it, and saving build artifacts in a GitHub release.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Direct publishing&lt;/strong&gt;: Artifacts are published directly to the Chrome Web Store, Mozilla Add-on Store, and Edge Partner Center.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One-time setup&lt;/strong&gt;: Once set up, you only need to cut a new release on GitHub to initiate the entire process.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Signed artifacts&lt;/strong&gt;: The action generates signed artifacts, attaches them to the release, and makes them available for users to download, inspect, or run locally without using a web store.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This guide will demonstrate gathering the necessary API keys and metadata, setting up each component of the pipeline, and automating the entire deployment process for your web extension.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before automating your web extension deployment, please ensure you have completed the following prerequisites:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Have a Web Extension&lt;/strong&gt;: You may choose to create a simple extension using various tools such as &lt;a href="https://extension.js.org/docs" rel="noopener noreferrer"&gt;Extension.js&lt;/a&gt; or adapt an existing project that adheres to manifest v3 requirements. While this guide demonstrates using &lt;a href="https://extension.js.org/docs" rel="noopener noreferrer"&gt;Extension.js&lt;/a&gt;, it is not strictly required for the deployment process.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Manually Publish the First Version&lt;/strong&gt;: The initial publication process is essential for setting up your extension on each platform. Depending on the store, this process may take varying amounts of time:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Chrome Web Store&lt;/strong&gt;: Typically 1-3 days for review and approval.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mozilla Add-on Store&lt;/strong&gt;: Usually 1-2 days.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Microsoft Edge Add-ons&lt;/strong&gt;: Initial reviews may take 4-7 days.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Once the initial build has been successfully published for review, proceed with gathering the required credentials to set up the automations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Accumulating Credentials
&lt;/h2&gt;

&lt;p&gt;To automate deploying your web extension to multiple browser web stores, we need API keys and some store-specific metadata for each store's APIs. Collect these credentials as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Add them to your Repository Secrets as you go&lt;/strong&gt;: You can find the &lt;strong&gt;Actions Secrets&lt;/strong&gt; section in your GitHub repository settings under &lt;code&gt;github.com/&amp;lt;user&amp;gt;/&amp;lt;repo&amp;gt;/settings/secrets/actions&lt;/code&gt;. Add all the collected keys and metadata to the &lt;strong&gt;Repository secrets&lt;/strong&gt; under the &lt;strong&gt;Secrets&lt;/strong&gt; tab.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Chrome Web Store Credentials
&lt;/h3&gt;

&lt;p&gt;To publish on the Chrome Web Store, you’ll need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Extension ID&lt;/strong&gt;: Available on your extension's product page. Open the Chrome Web Store, find your extension, and view its URL. The ID is the long string of characters at the end of the URL.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API Credentials&lt;/strong&gt;: Set up through the Chrome Web Store API in Google Cloud. Follow &lt;a href="https://developer.chrome.com/docs/webstore/using-api" rel="noopener noreferrer"&gt;these instructions&lt;/a&gt; to obtain:

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;CHROME_CLIENT_ID&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CHROME_CLIENT_SECRET&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CHROME_REFRESH_TOKEN&lt;/code&gt;
If you have trouble getting the &lt;em&gt;Refresh Token&lt;/em&gt;, give it some time and try again. It can take an hour or so after setting up access to the &lt;strong&gt;Chrome Web Store API&lt;/strong&gt; before it works in some cases.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Microsoft Edge Web Store Credentials
&lt;/h3&gt;

&lt;p&gt;To automate publishing to the Microsoft Edge Add-ons store, use the Edge Add-ons REST API:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Sign in to the Partner Center at &lt;a href="https://partner.microsoft.com/" rel="noopener noreferrer"&gt;partner.microsoft.com&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Visit the &lt;a href="https://partner.microsoft.com/en-us/dashboard/microsoftedge/publishapi" rel="noopener noreferrer"&gt;Publish API page&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create API credentials&lt;/strong&gt; to generate:

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;EDGE_CLIENT_ID&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;EDGE_CLIENT_SECRET&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ACCESS_TOKEN_URL&lt;/code&gt;
Additionally, you’ll need the &lt;strong&gt;Product ID&lt;/strong&gt;:&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Navigate to the &lt;strong&gt;Edge Overview&lt;/strong&gt; page.&lt;/li&gt;
&lt;li&gt;Click on your extension to find the &lt;strong&gt;Product ID&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Firefox Add-on Store Credentials
&lt;/h3&gt;

&lt;p&gt;For Firefox, use &lt;code&gt;webext&lt;/code&gt;, the preferred tool for automated deployments:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Log in to &lt;a href="https://addons.mozilla.org" rel="noopener noreferrer"&gt;addons.mozilla.org&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Go to &lt;strong&gt;Tools &amp;gt; Manage API Keys&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Agree to the terms and retrieve your &lt;strong&gt;Issuer ID&lt;/strong&gt; and &lt;strong&gt;Secret&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;FIREFOX_ISSUER&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;FIREFOX_SECRET&lt;/code&gt;
Once you are done collecting all of the necessary keys and metadata, your Repository Secrets should look similar to this:&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&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%2Fh4lwcxedi8wga0v0i2mb.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%2Fh4lwcxedi8wga0v0i2mb.png" alt="correctly configured api keys" width="789" height="441"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Building the Github Actions Workflow
&lt;/h2&gt;

&lt;p&gt;Now that we have accumulated all of the information we need to use our publishing APIs, it is time to build the workflow. First, create a new file in your repository's &lt;code&gt;.github/workflows&lt;/code&gt; directory with a name such as &lt;code&gt;release.yml&lt;/code&gt;. &lt;br&gt;
Let's review the workflow plan before we get started.&lt;/p&gt;

&lt;p&gt;### Workflow Summary&lt;/p&gt;

&lt;p&gt;The workflow will be triggered upon &lt;strong&gt;Release&lt;/strong&gt; of the project. This action implies that a tag and release have been created for a specific commit, followed by publishing the release.&lt;/p&gt;

&lt;p&gt;Note: You may choose alternative methods to release your extension. If you do, ensure to skip the section regarding the automatic upload of build artifacts to the release after publication.&lt;/p&gt;

&lt;p&gt;Advantages of this approach include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Automatically generated change logs for each release, based on GitHub's git history.&lt;/li&gt;
&lt;li&gt;Ability to keep certain versions of the extension available on the release page for future use, such as debugging older versions or providing transparency to users.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In detail, the workflow will perform the following tasks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run upon a published GitHub release&lt;/li&gt;
&lt;li&gt;Set up a build environment&lt;/li&gt;
&lt;li&gt;Checkout code and install dependencies&lt;/li&gt;
&lt;li&gt;Create builds for each target browser&lt;/li&gt;
&lt;li&gt;Publish builds to their respective webstores&lt;/li&gt;
&lt;li&gt;Upload build artifacts to the latest GitHub release (if applicable)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Configure the Workflow to Run on a Published Release
&lt;/h3&gt;

&lt;p&gt;Let's get started by giving our workflow a name and a hook.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Used by the Github Actions runner to describe the workflow&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Upload Release Build&lt;/span&gt;
&lt;span class="c1"&gt;# Configure the workflow to run when a new release has been published&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="na"&gt;release&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;types&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;published&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Setup Build Environment
&lt;/h3&gt;

&lt;p&gt;To ensure a smooth build process, let's set up our environment and run the builds for each browser:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Define a job named "release" that runs on an Ubuntu image&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;release&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Release&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# Checkout the latest code from the repository&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout code&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

      &lt;span class="c1"&gt;# Install Node.js&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup Node&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;18'&lt;/span&gt;

      &lt;span class="c1"&gt;# Create a directory for the builds&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Create directory&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cd ..; mkdir ./builds&lt;/span&gt;

      &lt;span class="c1"&gt;# Zip the source code (only needed if publishing to Firefox)&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Zip Source Code&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;zip -r ../builds/Source.zip .&lt;/span&gt;

      &lt;span class="c1"&gt;# Install project dependencies&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install Dependencies&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm ci&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Run Targeted Builds
&lt;/h3&gt;

&lt;p&gt;Depending on the bundler or framework being used, production builds will be triggered via your package file scripts. Since this example utilizes &lt;a href="https://extension.js.org/docs" rel="noopener noreferrer"&gt;Extension.js&lt;/a&gt;, I've included the following build scripts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"build:ci:chrome"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"extension build --browser chrome --polyfill"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"build:ci:firefox"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"extension build --browser firefox --polyfill"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"build:ci:edge"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"extension build --browser edge --polyfill"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Upload Bundles and Publish
&lt;/h3&gt;

&lt;p&gt;Here's where the magic happens! We'll run through each target browser, automatically deploying to their respective webstores that have been configured.&lt;/p&gt;

&lt;h4&gt;
  
  
  Automate Release to the Firefox Add-on Store
&lt;/h4&gt;

&lt;p&gt;This section will sign, upload, and publish our extension artifacts to the Firefox Add-on Store. You'll need to be sure to have &lt;a href="https://extensionworkshop.com/documentation/develop/getting-started-with-web-ext/" rel="noopener noreferrer"&gt;web-ext&lt;/a&gt; as a &lt;code&gt;devDependency&lt;/code&gt; in your package file. You can install it with &lt;code&gt;npm install -D web-ext&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Sign &amp;amp; Upload Firefox artifacts&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Sign and Publish artifact&lt;/span&gt;
&lt;span class="na"&gt;continue-on-error&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;FIREFOX_ISSUER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.FIREFOX_ISSUER }}&lt;/span&gt;
  &lt;span class="na"&gt;FIREFOX_SECRET&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.FIREFOX_SECRET }}&lt;/span&gt;
&lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npx web-ext sign --channel listed -s ./dist/firefox/ --upload-source-code ../builds/Source.zip --artifacts-dir ./dist/firefox --api-key $FIREFOX_ISSUER --api-secret $FIREFOX_SECRET&lt;/span&gt;
&lt;span class="c1"&gt;# Move the artifact to a more appropriate name&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Move artifact&lt;/span&gt;
&lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mv ./dist/firefox/&amp;lt;your-app&amp;gt;-*.xpi ./builds/FirefoxExtension.xpi&lt;/span&gt;
&lt;span class="c1"&gt;# Upload the Firefox extension to the release&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Upload FirefoxExtension to release&lt;/span&gt;
&lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Shopify/upload-to-release@07611424e04f1475ddf550e1c0dd650b867d5467&lt;/span&gt;
&lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;FirefoxExtension.xpi&lt;/span&gt;
  &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./builds/FirefoxExtension.xpi&lt;/span&gt;
  &lt;span class="na"&gt;repo-token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Automate Release to the Chrome WebStore
&lt;/h4&gt;

&lt;p&gt;This section will package, upload, and publish our extension artifacts to the Google Chrome Web Store&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Zip the Chrome artifacts&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Zip Chrome Artifacts&lt;/span&gt;
&lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cd ./dist/chrome ; zip -r ../../builds/ChromeExtension.zip *&lt;/span&gt;
&lt;span class="c1"&gt;# Upload the Chrome extension to the release&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Upload ChromeExtension to release&lt;/span&gt;
&lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Shopify/upload-to-release@07611424e04f1475ddf550e1c0dd650b867d5467&lt;/span&gt;
&lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ChromeExtension.zip&lt;/span&gt;
  &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./builds/ChromeExtension.zip&lt;/span&gt;
  &lt;span class="na"&gt;repo-token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;
&lt;span class="c1"&gt;# Publish the extension to the Chrome Web Store&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Publish to Chrome Web Store&lt;/span&gt;
&lt;span class="na"&gt;continue-on-error&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;wdzeng/chrome-extension@v1&lt;/span&gt;
&lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;client-id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.CHROME_CLIENT_ID }}&lt;/span&gt;
  &lt;span class="na"&gt;client-secret&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.CHROME_CLIENT_SECRET }}&lt;/span&gt;
  &lt;span class="na"&gt;refresh-token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.CHROME_REFRESH_TOKEN }}&lt;/span&gt;
  &lt;span class="na"&gt;zip-path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;./builds/ChromeExtension.zip'&lt;/span&gt;
  &lt;span class="na"&gt;extension-id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;your-chrome-extension-id&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Automate Release to the Edge Add-on Store
&lt;/h4&gt;

&lt;p&gt;This section will package, upload, and publish our extension artifacts to the Microsoft Edge Add-on Store&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Upload Edge artifacts&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Zip Edge Artifacts&lt;/span&gt;
&lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cd ./dist/edge ; zip -r ../../builds/EdgeExtension.zip *&lt;/span&gt;
&lt;span class="c1"&gt;# Upload the Edge extension to the release&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Upload EdgeExtension to release&lt;/span&gt;
&lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Shopify/upload-to-release@07611424e04f1475ddf550e1c0dd650b867d5467&lt;/span&gt;
&lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;EdgeExtension.zip&lt;/span&gt;
  &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./builds/EdgeExtension.zip&lt;/span&gt;
  &lt;span class="na"&gt;repo-token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;
&lt;span class="c1"&gt;# Publish the extension to the Edge Addon Store&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Publish to Edge Addon Store&lt;/span&gt;
&lt;span class="na"&gt;continue-on-error&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;wdzeng/edge-addon@v2&lt;/span&gt;
&lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;product-id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;your-edge-addon-id&amp;gt;&lt;/span&gt;
  &lt;span class="na"&gt;zip-path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./builds/EdgeExtension.zip&lt;/span&gt;
  &lt;span class="na"&gt;api-key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.EDGE_CLIENT_SECRET }}&lt;/span&gt;
  &lt;span class="na"&gt;client-id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.EDGE_CLIENT_ID }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Test the Workflow
&lt;/h3&gt;

&lt;p&gt;Testing your new GitHub Actions workflow is essential to ensure it functions as intended and avoids any issues upon deployment. Here's an easy-to-follow guide on testing your workflows locally before pushing them to the main repository:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Create a Test Branch&lt;/strong&gt;: Start by creating a separate branch, ideally named &lt;code&gt;workflow-test&lt;/code&gt;, to isolate any changes related to the workflow from your production code. This ensures that any potential issues will not impact your live application.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Add your Modifications&lt;/strong&gt;: Commit the new &lt;code&gt;release.yml&lt;/code&gt; file to your test branch and push it to the GitHub remote branch.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Enable Local Runs&lt;/strong&gt;: Navigate to your repository's settings page, select &lt;code&gt;Code&lt;/code&gt; in the left-hand menu, click on &lt;code&gt;Actions&lt;/code&gt;, then click on &lt;code&gt;General&lt;/code&gt;. Scroll down to the "Local environment" section, and enable "Allow local runs". This enables you to run your workflow locally.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Run Workflow Locally&lt;/strong&gt;: You can now execute the workflow locally by using GitHub CLI or running the workflow file in your local GitHub Actions runner.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Validate Test Results&lt;/strong&gt;: Review the output from the locally executed workflow to ensure it behaves as intended. Address any issues or errors that may have arisen during testing before merging your changes into the main branch.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Remember to be patient! I almost always run into small configuration issues the first few times I write a new pipeline. If you run into any issues, feel free to mention me on GitHub and I'll try to help in any way I can.&lt;br&gt;
If you still need some more help, you can checkout a simple working example from the &lt;a href="https://github.com/jellyfith/linkedzen" rel="noopener noreferrer"&gt;LinkedZen&lt;/a&gt; extension on my GitHub.&lt;/p&gt;
&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;Once everything is configured, your pipeline should look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Upload Release Build&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;release&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;types&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;published&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;release&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Release&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# Checkout the code&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout code&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup Node&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;18'&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Create directory&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cd ..; mkdir ./builds&lt;/span&gt;

      &lt;span class="c1"&gt;# Zip the source code&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Zip Source&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;zip -r ../builds/Source.zip *&lt;/span&gt;

      &lt;span class="c1"&gt;# Install dependencies&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install dependencies&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm ci&lt;/span&gt;

      &lt;span class="c1"&gt;# Create build directory&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Create build directory&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mkdir ./builds&lt;/span&gt;

      &lt;span class="c1"&gt;# Build for Firefox, Chrome and Edge&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build for Firefox&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run build:ci:firefox&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build for Chrome&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run build:ci:chrome&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build for Edge&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run build:ci:edge&lt;/span&gt;

      &lt;span class="c1"&gt;# Sign &amp;amp; Upload Firefox artifacts&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Sign and Publish artifact&lt;/span&gt;
        &lt;span class="na"&gt;continue-on-error&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;FIREFOX_ISSUER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.FIREFOX_ISSUER }}&lt;/span&gt;
          &lt;span class="na"&gt;FIREFOX_SECRET&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.FIREFOX_SECRET }}&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npx web-ext sign --channel listed -s ./dist/firefox/ --upload-source-code  ../builds/Source.zip --artifacts-dir ./dist/firefox --api-key $FIREFOX_ISSUER --api-secret $FIREFOX_SECRET&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Move artifact&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mv ./dist/firefox/&amp;lt;your-extension&amp;gt;-*.xpi ./builds/FirefoxExtension.xpi&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Upload FirefoxExtension to release&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Shopify/upload-to-release@07611424e04f1475ddf550e1c0dd650b867d5467&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;FirefoxExtension.xpi&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./builds/FirefoxExtension.xpi&lt;/span&gt;
          &lt;span class="na"&gt;repo-token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Zip Chrome Artifacts&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cd ./dist/chrome ; zip -r ../../builds/ChromeExtension.zip *&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Upload ChromeExtension to release&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Shopify/upload-to-release@07611424e04f1475ddf550e1c0dd650b867d5467&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ChromeExtension.zip&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./builds/ChromeExtension.zip&lt;/span&gt;
          &lt;span class="na"&gt;repo-token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Publish to Chrome Web Store&lt;/span&gt;
        &lt;span class="na"&gt;continue-on-error&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;wdzeng/chrome-extension@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;client-id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.CHROME_CLIENT_ID }}&lt;/span&gt;
          &lt;span class="na"&gt;client-secret&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.CHROME_CLIENT_SECRET }}&lt;/span&gt;
          &lt;span class="na"&gt;refresh-token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.CHROME_REFRESH_TOKEN }}&lt;/span&gt;
          &lt;span class="na"&gt;zip-path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./builds/ChromeExtension.zip&lt;/span&gt;
          &lt;span class="na"&gt;extension-id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;your chrome extensions id&amp;gt;&lt;/span&gt;

      &lt;span class="c1"&gt;# Upload Edge artifacts&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Zip Edge Artifacts&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cd ./dist/edge ; zip -r ../../builds/EdgeExtension.zip *&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Upload EdgeExtension to release&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Shopify/upload-to-release@07611424e04f1475ddf550e1c0dd650b867d5467&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;EdgeExtension.zip&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./builds/EdgeExtension.zip&lt;/span&gt;
          &lt;span class="na"&gt;repo-token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Publish to Edge Addon Store&lt;/span&gt;
        &lt;span class="na"&gt;continue-on-error&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;wdzeng/edge-addon@v2&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;product-id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;your edge product id&amp;gt;&lt;/span&gt;
          &lt;span class="na"&gt;zip-path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./builds/EdgeExtension.zip&lt;/span&gt;
          &lt;span class="na"&gt;api-key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.EDGE_CLIENT_SECRET }}&lt;/span&gt;
          &lt;span class="na"&gt;client-id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.EDGE_CLIENT_ID }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>tutorial</category>
      <category>github</category>
      <category>webdev</category>
      <category>extensions</category>
    </item>
  </channel>
</rss>
