<?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: Álvaro F. P. P."</title>
    <description>The latest articles on DEV Community by Álvaro F. P. P." (@alvarofpp).</description>
    <link>https://dev.to/alvarofpp</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%2F409012%2F33eb2e39-582e-4a5f-bb6e-87a26e89fb9b.jpg</url>
      <title>DEV Community: Álvaro F. P. P."</title>
      <link>https://dev.to/alvarofpp</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/alvarofpp"/>
    <language>en</language>
    <item>
      <title>Como criar um repositório para gestão de recursos do GitHub com o Pulumi</title>
      <dc:creator>Álvaro F. P. P."</dc:creator>
      <pubDate>Sun, 06 Apr 2025 15:01:06 +0000</pubDate>
      <link>https://dev.to/alvarofpp/como-criar-um-repositorio-para-gestao-de-recursos-do-github-com-o-pulumi-2o6n</link>
      <guid>https://dev.to/alvarofpp/como-criar-um-repositorio-para-gestao-de-recursos-do-github-com-o-pulumi-2o6n</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;🇺🇸 To read in English: &lt;a href="https://dev.to/alvarofpp/how-to-create-a-github-resource-management-repository-with-pulumi-38l2"&gt;How to create a GitHub resource management repository with Pulumi&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Gerenciar infraestrutura como código (IaC, &lt;em&gt;Infrastructure as Code&lt;/em&gt;) se tornou uma prática essencial para equipes de desenvolvimento modernas, e o Pulumi surge como uma ferramenta poderosa nesse cenário, permitindo definir recursos em linguagens de programação que você já conhece - seja Python, JavaScript, TypeScript, Go ou C#.&lt;/p&gt;

&lt;p&gt;Se você já utiliza o GitHub para controle de versão e colaboração, talvez esteja se perguntando como integrar seus recursos existentes (repositórios, organizações, membros, etc) ao fluxo de trabalho do Pulumi. A boa notícia é que o Pulumi oferece mecanismos para importar e gerenciar esses recursos, permitindo que você aproveite a infraestrutura existente sem precisar recriá-la do zero.&lt;/p&gt;

&lt;p&gt;Nesta postagem, vamos explorar o processo de criar um repositório que nos permita gerenciar recursos do GitHub, desde repositórios individuais até estruturas organizacionais (quase) completas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Motivação
&lt;/h2&gt;

&lt;p&gt;No meu caso, a minha principal motivação é a minha bagunça. Atualmente tenho 126 repositórios pessoais na minha conta do GitHub, além de fazer parte de 14 organizações, dos quais alguns eu sou o responsável pela parte de Ops. Fazer a gestão de acessos, licenças, workflows, entre outras coisas vem se tornando uma tarefa bastante onerosa.&lt;/p&gt;

&lt;p&gt;Além disso, no último semestre tenho trabalhado diariamente com o AWS CDK (&lt;em&gt;Cloud Development Kit&lt;/em&gt;), uma ferramenta da AWS que permite definir infraestrutura na nuvem usando linguagens de programação como TypeScript. Comparado com os anos que trabalhei com Terraform, que utiliza HCL (&lt;em&gt;HashiCorp Configuration Language&lt;/em&gt;), uma linguagem declarativa específica para definir infraestrutura como código, posso afirmar que tenho gostado muito mais de usar uma linguagem de programação convencional para gerir a infraestrutura do que o HCL.&lt;/p&gt;

&lt;p&gt;Sendo assim, o Pulumi se apresentou como uma ótima opção de uso. Ele me permite reutilizar minha estrutura para projetos em TypeScript (como linter, CI/CD, etc), resolve meu problema de gestão de infraestrutura e possibilita descrever cenários mais dinâmicamente do que antes (creio que uma das principais vantagens de se usar uma linguagem de programação para isso).&lt;/p&gt;

&lt;h2&gt;
  
  
  Considerações
&lt;/h2&gt;

&lt;p&gt;Antes de prosseguirmos, quero descrever algumas considerações para esse artigo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Você precisa ter o Pulumi instalado na sua máquina: &lt;a href="https://www.pulumi.com/docs/iac/download-install/" rel="noopener noreferrer"&gt;Download &amp;amp; install Pulumi&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;A linguagem de programação que irei utilizar será TypeScript.&lt;/li&gt;
&lt;li&gt;Todo o passo a passo será feito em um diretório inicialmente vazio.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Preparando o projeto
&lt;/h2&gt;

&lt;p&gt;Caso não queira fazer o passo a passo dessa seção, você pode usar o meu template:&lt;/p&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/alvarofpp" rel="noopener noreferrer"&gt;
        alvarofpp
      &lt;/a&gt; / &lt;a href="https://github.com/alvarofpp/template-infra-pulumi" rel="noopener noreferrer"&gt;
        template-infra-pulumi
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Template for IaC projects using Pulumi.
    &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;Template for IaC using Pulumi&lt;/h1&gt;

&lt;/div&gt;
&lt;p&gt;This template comes with a structure for you to manage your personal
repositories or organizations on GitHub, as well as making it easy to expand to
other contexts.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Migrating GitHub resources to Pulumi&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;You can use the &lt;a href="https://github.com/alvarofpp/import-from-github-to-pulumi" rel="noopener noreferrer"&gt;alvarofpp/import-from-github-to-pulumi&lt;/a&gt; repository
to perform the migration of an organization or your personal repositories to
Pulumi.&lt;/p&gt;
&lt;/div&gt;



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


&lt;p&gt;Perceba que para cada conta será um diretório com um projeto em TypeScript, com seus próprios arquivos &lt;code&gt;package.json&lt;/code&gt; e afins. No meu caso, será um projeto para meus repositórios pessoais e um projeto para cada organização. O passo a passo para preparar o projeto é o mesmo em todos esses casos.&lt;/p&gt;

&lt;h3&gt;
  
  
  Criando um projeto no Pulumi
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Use o login local do Pulumi:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pulumi login file:&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;O comando &lt;code&gt;pulumi login&lt;/code&gt; é usado para autenticar sua CLI do Pulumi com um backend de armazenamento de estado. Por padrão, você se conecta ao backend gerenciado na &lt;a href="//app.pulumi.com"&gt;nuvem do Pulumi&lt;/a&gt;. Quando usamos &lt;code&gt;file:$(pwd)&lt;/code&gt;, você configura o Pulumi para usar um backend de arquivo local em vez do backend na nuvem.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Inicie um projeto no Pulumi:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pulumi new typescript &lt;span class="nt"&gt;--force&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Precisamos usar o &lt;code&gt;--force&lt;/code&gt; porque o comando &lt;code&gt;login&lt;/code&gt; irá criar um diretório &lt;code&gt;home&lt;/code&gt; e o comando &lt;code&gt;new&lt;/code&gt; exige ser executado em um diretório vazio.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Instale o provedor do GitHub:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @pulumi/github
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Adicione o token do GitHub:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pulumi config &lt;span class="nb"&gt;set &lt;/span&gt;github:token &amp;lt;token&amp;gt; &lt;span class="nt"&gt;--secret&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Caso não saiba como criar um token de acesso para a API do GitHub, consulte a documentação oficial: &lt;a href="https://docs.github.com/pt/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens" rel="noopener noreferrer"&gt;Gerenciar seus tokens de acesso pessoal&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Adicione o &lt;code&gt;owner&lt;/code&gt; (pode ser um usuário ou uma organização):&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pulumi config &lt;span class="nb"&gt;set &lt;/span&gt;github:owner &amp;lt;owner&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

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

&lt;p&gt;Até aqui o seu diretório deve estar próximo disso:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.
├── Pulumi.main.yaml
├── Pulumi.yaml
├── index.ts
├── package-lock.json
├── package.json
└── tsconfig.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Tornando o projeto mais dinâmico
&lt;/h3&gt;

&lt;p&gt;Como terei inúmeros recursos, não é interessante ter que usar um esquema de importação convencional, pois implicaria em sempre ter que importar um novo repositório quando criado, além dos mais de 120 repositórios que já tenho. Ao invés disso, optei por importar dinâmicamente os recursos.&lt;/p&gt;

&lt;p&gt;O objetivo é ter diretórios para cada tipo de recurso e uma forma dinâmica de importarmos esses recursos.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Crie um arquivo &lt;code&gt;registry.ts&lt;/code&gt; com o seguinte conteúdo:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;path&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;pulumi&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@pulumi/pulumi&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;RegistryBaseConstructor&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;new &lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;RegistryBase&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RegistryBase&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;suffix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;directory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;suffix&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;directory&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;ResourceRegistry&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;ResourceRegistry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;ResourceClass&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ResourceClass&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Critical error in init method: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;suffix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;directory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;anyResourceRegistry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;RegistryBaseConstructor&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;classesDir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;directory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readdirSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;classesDir&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;endsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;index.ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;suffix&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;modulePath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;classesDir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

          &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="kr"&gt;module&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;modulePath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Class&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;module&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
            &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Class&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="nx"&gt;anyResourceRegistry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Class&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Failed to register &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; class:`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;anyResourceRegistry&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;A classe &lt;code&gt;RegistryBase&lt;/code&gt; será nossa classe base para as classes que conterão cada tipo de recurso. A função dela é ser um registry de recursos. A busca por esses recursos será dinâmica, atendendo dois critérios:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Os recursos precisam ter um sufixo previamente definido.&lt;/li&gt;
&lt;li&gt;Os recursos precisam estar no mesmo diretório que o registry.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Crie o diretório &lt;code&gt;repositories&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;repositories
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Crie o arquivo &lt;code&gt;repositories/index.ts&lt;/code&gt; com o seguinte conteúdo:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;RegistryBase&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../registry&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RepositoriesRegistry&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;RegistryBase&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Repository&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;A classe &lt;code&gt;RepositoriesRegistry&lt;/code&gt; irá conter todas as classes que possuem &lt;code&gt;Repository&lt;/code&gt; como sufixo e estejam dentro de &lt;code&gt;repositories/&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;No arquivo &lt;code&gt;index.ts&lt;/code&gt;, importe o &lt;code&gt;RepositoriesRegistry&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;RepositoriesRegistry&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./repositories&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;repositories&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;RepositoriesRegistry&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

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

&lt;blockquote&gt;
&lt;p&gt;❗ Para o caso de organizações, você deve repetir os passos 2 a 4 para &lt;code&gt;memberships&lt;/code&gt; (sufixo &lt;code&gt;Membership&lt;/code&gt;) e &lt;code&gt;teams&lt;/code&gt; (sufixo &lt;code&gt;Team&lt;/code&gt;).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Até aqui o seu diretório deve estar parecido com isso:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.
├── Pulumi.main.yaml
├── Pulumi.yaml
├── index.ts
├── memberships
│   └── index.ts
├── package-lock.json
├── package.json
├── repositories
│   └── index.ts
├── teams
│   └── index.ts
└── tsconfig.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Coletando dados e gerando os recursos no Pulumi
&lt;/h2&gt;

&lt;p&gt;Nós queremos que os recursos sejam os mais fidedignos do seu estado atual, pois caso não sejam isso pode acarretar em uma atualização não desejada de estado durante a importação ou o uso. Para isso podemos usar a API do GitHub para coletar os dados de cada recurso e declara-los no Pulumi.&lt;/p&gt;
&lt;h3&gt;
  
  
  Processo manual
&lt;/h3&gt;

&lt;p&gt;Aqui você deverá criar um script para coletar os dados da API do GitHub e atribuí-los aos recursos do Pulumi na linguagem de programação escolhida.&lt;/p&gt;

&lt;p&gt;Para repositórios:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Temos duas formas de listar os repositórios:

&lt;ul&gt;
&lt;li&gt;Para seus repositórios pessoais: &lt;code&gt;GET /user/repos?affiliation=owner&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Para os repositórios de uma organização: &lt;code&gt;GET /orgs/&amp;lt;org&amp;gt;/repos&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Itere sobre cada repositório e use os seguintes endpoints para coletar dados mais detalhados:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;GET /repos/&amp;lt;user_or_org&amp;gt;/&amp;lt;repository_name&amp;gt;&lt;/code&gt;: para dados gerais sobre o repositório.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GET /repos/&amp;lt;repository_name&amp;gt;/pages&lt;/code&gt;: para dados sobre as páginas do repositório.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Para membros de uma organização:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;GET /orgs/&amp;lt;org&amp;gt;/members&lt;/code&gt; para listar os membros da organização.&lt;/li&gt;
&lt;li&gt;Itere sobre cada membro e faça uma chamada para o endpoint &lt;code&gt;GET /orgs/&amp;lt;org&amp;gt;/memberships/&amp;lt;member&amp;gt;&lt;/code&gt; para coletar dados de associação daquele usuário com a organização.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Para times de uma organização:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;GET /orgs/&amp;lt;org&amp;gt;/teams&lt;/code&gt; para listar os times da organização.&lt;/li&gt;
&lt;li&gt;Itere sobre cada time e use os seguintes endpoints para coletar dados mais detalhados:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;GET /orgs/&amp;lt;org&amp;gt;/teams/&amp;lt;team&amp;gt;&lt;/code&gt; para dados gerais do time.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GET /orgs/&amp;lt;org&amp;gt;/teams/&amp;lt;team&amp;gt;/repos&lt;/code&gt; para listar os repositórios do time.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GET /orgs/&amp;lt;org&amp;gt;/teams/&amp;lt;team&amp;gt;/members&lt;/code&gt; para listar os membros daquele time. Itere sobre cada membro do time:

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;GET /orgs/&amp;lt;org&amp;gt;/teams/&amp;lt;team&amp;gt;/memberships/&amp;lt;member&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Agora que você tem todos os dados necessários, basta atribuí-los para os respectivos recursos no Pulumi:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Repositório: &lt;a href="https://www.pulumi.com/registry/packages/github/api-docs/repository/" rel="noopener noreferrer"&gt;github.Repository&lt;/a&gt;.

&lt;ul&gt;
&lt;li&gt;Branch do repositório: &lt;a href="https://www.pulumi.com/registry/packages/github/api-docs/branch/" rel="noopener noreferrer"&gt;github.Branch&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Branch padrão (para o caso de repositórios não arquivados): &lt;a href="https://www.pulumi.com/registry/packages/github/api-docs/branchdefault/" rel="noopener noreferrer"&gt;github.BranchDefault&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Membros da organização: &lt;a href="https://www.pulumi.com/registry/packages/github/api-docs/membership/" rel="noopener noreferrer"&gt;github.Membership&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Times da organização: &lt;a href="https://www.pulumi.com/registry/packages/github/api-docs/team/" rel="noopener noreferrer"&gt;github.Team&lt;/a&gt;.

&lt;ul&gt;
&lt;li&gt;Repositórios do time: &lt;a href="https://www.pulumi.com/registry/packages/github/api-docs/teamrepository/" rel="noopener noreferrer"&gt;github.TeamRepository&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Para membros do time, você tem duas formas (eu prefiro a primeira por ser mais simples):

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.pulumi.com/registry/packages/github/api-docs/teammembers/" rel="noopener noreferrer"&gt;github.TeamMembers&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.pulumi.com/registry/packages/github/api-docs/teammembership/" rel="noopener noreferrer"&gt;github.TeamMembership&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Importando usando repositório
&lt;/h3&gt;

&lt;p&gt;Para abstrair todo esse passo a passo de coleta de dados do GitHub e montagem dos recursos do Pulumi que vimos anteriormente, criei o seguinte repositório:&lt;/p&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/alvarofpp" rel="noopener noreferrer"&gt;
        alvarofpp
      &lt;/a&gt; / &lt;a href="https://github.com/alvarofpp/import-from-github-to-pulumi" rel="noopener noreferrer"&gt;
        import-from-github-to-pulumi
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Scripts to import resources from organizations and personal projects on GitHub into Pulumi.
    &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;Import from GitHub to Pulumi&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;This repository contains a configured Docker image with scripts to import your personal
repositories or repositories, members and teams of an organization into Pulumi.&lt;/p&gt;
&lt;p&gt;After running the import script, two sets of artifacts are generated
and saved in the &lt;code&gt;resources/&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;import_*.txt&lt;/code&gt;: files with commands for importing resources.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;members/*.ts&lt;/code&gt;, &lt;code&gt;repositories/*.ts&lt;/code&gt; and &lt;code&gt;teams/*.ts&lt;/code&gt;: Pulumi resource files.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;a href="https://github.com/alvarofpp/template-infra-pulumi" rel="noopener noreferrer"&gt;alvarofpp/template-infra-pulumi&lt;/a&gt; repository has a directory structure
that you can use as a basis.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;How to use&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;This repository can be used for two purposes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Importing your personal repositories.&lt;/li&gt;
&lt;li&gt;Importing members of an organization's repositories and teams.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For both cases, you first need to run &lt;code&gt;make build&lt;/code&gt; to generate the
Docker image that will be used to run the scripts.&lt;/p&gt;
&lt;p&gt;The commands using &lt;code&gt;make&lt;/code&gt; that will be shown below can be found in the &lt;code&gt;Makefile&lt;/code&gt; file
If you choose not to use the &lt;a href="https://github.com/alvarofpp/import-from-github-to-pulumi/%60Makefile%60" rel="noopener noreferrer"&gt;Makefile&lt;/a&gt;, you can…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/alvarofpp/import-from-github-to-pulumi" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Nesse repositório, você terá uma imagem Docker configurada e com scripts para gerar os arquivos dos recursos para o Pulumi com base nos dados retornados pela a API do GitHub.&lt;/p&gt;

&lt;p&gt;Para esse repositório funcionar, você deve ter o Docker e o &lt;code&gt;make&lt;/code&gt; instalado na sua máquina. Se você usa Linux, provavelmente já tem o &lt;code&gt;make&lt;/code&gt; instalado.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ Caso você esteja importando contas e organizações em sequência, após cada importação você pode usar o comando &lt;code&gt;make clear&lt;/code&gt; para limpar os logs e arquivos gerados durante a importação anterior.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Em um outro diretório, clone o repositório:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone git@github.com:alvarofpp/import-from-github-to-pulumi.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Gerando os arquivos de repositórios pessoais
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Exporte o token de acesso ao GitHub:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;GITHUB_ACCESS_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;github_pat_...
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Exporte o seu usuário no GitHub:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;GITHUB_USER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;...
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Execute o comando de gerar os arquivos para o Pulumi:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;make import-my-repos
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;No diretório &lt;code&gt;resources&lt;/code&gt; terá os seguintes arquivos:&lt;br&gt;
    - &lt;code&gt;import_*.txt&lt;/code&gt;: arquivo com os comandos de importação.&lt;br&gt;
    - &lt;code&gt;repositories/*.ts&lt;/code&gt;: arquivos com os recursos para cada repositório.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Gerando os arquivos de repositórios, membros e times de uma organização
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Exporte o token de acesso ao GitHub:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;GITHUB_ACCESS_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;github_pat_...
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Exporte o nome da organização no GitHub:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;GITHUB_ORG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;...
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Execute o comando de gerar os arquivos para o Pulumi:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;make import-org
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;No diretório &lt;code&gt;resources&lt;/code&gt; terá os seguintes arquivos:&lt;br&gt;
    - &lt;code&gt;import_*.txt&lt;/code&gt;: arquivo com os comandos de importação.&lt;br&gt;
    - &lt;code&gt;memberships/*.ts&lt;/code&gt;: arquivos para cada membro da organização.&lt;br&gt;
    - &lt;code&gt;repositories/*.ts&lt;/code&gt;: arquivos para cada repositório da organização.&lt;br&gt;
    - &lt;code&gt;teams/*.ts&lt;/code&gt;: arquivos para cada time da organização.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Importando os recursos
&lt;/h2&gt;

&lt;p&gt;Caso você tenha coletado por conta própria os dados, então também deve montar os comandos de importação, sendo eles:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Repositório&lt;/span&gt;
pulumi import github:index/repository:Repository &amp;lt;resource_name&amp;gt; &amp;lt;repository&amp;gt;

&lt;span class="c"&gt;# Branch do repositório&lt;/span&gt;
pulumi import github:index/branch:Branch &amp;lt;resource_name&amp;gt; &amp;lt;repositorio&amp;gt;:&amp;lt;branch&amp;gt;

&lt;span class="c"&gt;# Membro de organização&lt;/span&gt;
pulumi import github:index/membership:Membership &amp;lt;resource_name&amp;gt; &amp;lt;org&amp;gt;:&amp;lt;member&amp;gt;

&lt;span class="c"&gt;# Time de organização&lt;/span&gt;
pulumi import github:index/team:Team &amp;lt;resource_name&amp;gt; &amp;lt;team_id&amp;gt;

&lt;span class="c"&gt;# Membros do time&lt;/span&gt;
pulumi import github:index/teamMembers:TeamMembers &amp;lt;resource_name&amp;gt; &amp;lt;team_id&amp;gt;

&lt;span class="c"&gt;# Repositório do time&lt;/span&gt;
pulumi import github:index/teamRepository:TeamRepository &amp;lt;resource_name&amp;gt; &amp;lt;team_id&amp;gt;:&amp;lt;repository&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Caso você tenha optado por usar o repositório que sugeri anteriormente, o passo a passo é:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Copie os arquivos &lt;code&gt;*.ts&lt;/code&gt; para os seus respectivos diretórios do projeto do Pulumi.&lt;/li&gt;
&lt;li&gt;Execute todos os comandos nos arquivos &lt;code&gt;import_*.txt&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Agora execute &lt;code&gt;pulumi up&lt;/code&gt; e aplique as atualizações, caso haja.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Pronto, a partir de agora você terá um projeto que possibilita gerir seus recursos do GitHub usando o Pulumi. Lembre-se que essa estrutura pode ser expandida para outros tipos de recursos e que você está usando uma linguagem de programação para isso, então automações com scripts funcionam muito bem nesse contexto.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dicas e sugestões
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Perceba que usamos o login local do Pulumi, isso é apenas para facilitar a didática. Em um ambiente real, é preferível que você salve os estados no S3 ou serviço semelhante.&lt;/li&gt;
&lt;li&gt;A indentação dos códigos pode não está adequadamente alinhados, mas você pode usar um formatter/linter para consertar isso. No meu caso, uso o do Deno (&lt;code&gt;deno fmt&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Casos de uso
&lt;/h2&gt;

&lt;p&gt;Existem vários casos de uso e isso depende do seu contexto ou do contexto da organização. Aqui irei listar apenas alguns casos de uso que são principalmente uteis para contas pessoais.&lt;/p&gt;

&lt;h3&gt;
  
  
  Atualização de arquivos especificos
&lt;/h3&gt;

&lt;p&gt;Com o recurso &lt;code&gt;RepositoryFile&lt;/code&gt; você consegue gerenciar arquivos especificos nos seus repositórios. Exemplos de arquivos interessantes para usar esse recurso são &lt;code&gt;LICENSE&lt;/code&gt; e também workflows. Este último tipo de arquivo (workflows) é bastante útil para contas pessoais, pois o GitHub permite compartilhar actions e workflows em organizações, porém não em contas pessoais.&lt;/p&gt;

&lt;h3&gt;
  
  
  Atualização de repositórios para ocasiões especiais
&lt;/h3&gt;

&lt;p&gt;Eu possuo alguns repositórios que participam do Hacktoberfest. Portanto pretendo colocar uma verificação de data para que todo início de outubro adicione o tópico &lt;code&gt;hacktoberfest&lt;/code&gt; no repositório e em todo início de novembro remova esse tópico.&lt;/p&gt;

&lt;h3&gt;
  
  
  Gestão de compartilhamentos e acessos
&lt;/h3&gt;

&lt;p&gt;Agora ficou mais fácil definir quais contas fazem parte da sua organização, seus privilégios, quais times tem acessos a quais repositórios, etc.&lt;/p&gt;

&lt;h3&gt;
  
  
  Gestão de variáveis e segredos
&lt;/h3&gt;

&lt;p&gt;Se você usa o GitHub Actions, deve estar familiarizado com o uso de variáveis e segredos nos seus workflows. Uma boa prática é colocar um tempo de expiração curto em segredos e renova-los sempre que possível. O Pulumi permite que você armazene segredos na stack, o comando de inserir o token do GitHub no projeto é um exemplo disso, portando você pode integrar essa funcionalidade com um script de renovação de token. Toda vez que o script é executado, ele automaticamente atualiza o token na stack e atualiza o segredo no repositório.&lt;/p&gt;

</description>
      <category>github</category>
      <category>pulumi</category>
      <category>iac</category>
      <category>howto</category>
    </item>
    <item>
      <title>How to create a GitHub resource management repository with Pulumi</title>
      <dc:creator>Álvaro F. P. P."</dc:creator>
      <pubDate>Sun, 06 Apr 2025 15:00:25 +0000</pubDate>
      <link>https://dev.to/alvarofpp/how-to-create-a-github-resource-management-repository-with-pulumi-38l2</link>
      <guid>https://dev.to/alvarofpp/how-to-create-a-github-resource-management-repository-with-pulumi-38l2</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;🇧🇷 Para ler em Português: &lt;a href="https://dev.to/alvarofpp/como-criar-um-repositorio-para-gestao-de-recursos-do-github-com-o-pulumi-2o6n"&gt;Como criar um repositório para gestão de recursos do GitHub com o Pulumi&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Managing infrastructure as code (IaC) has become an essential practice for modern development teams, and Pulumi has emerged as a powerful tool in this scenario, allowing you to define resources in programming languages you already know - be it Python, JavaScript, TypeScript, Go or C#.&lt;/p&gt;

&lt;p&gt;If you already use GitHub for version control and collaboration, you may be wondering how to integrate your existing resources (repositories, organizations, members, etc.) into Pulumi's workflow. The good news is that Pulumi offers mechanisms for importing and managing these resources, allowing you to take advantage of existing infrastructure without having to recreate it from scratch.&lt;/p&gt;

&lt;p&gt;In this post, we'll explore the process of creating a repository that allows us to manage GitHub resources, from individual repositories to (almost) complete organizational structures.&lt;/p&gt;

&lt;h2&gt;
  
  
  Motivation
&lt;/h2&gt;

&lt;p&gt;In my case, my main motivation is my mess. I currently have 126 personal repositories on my GitHub account, as well as being part of 14 organizations, some of which I'm responsible for Ops. Managing access, licenses, workflows, among other things, has become a very onerous task.&lt;/p&gt;

&lt;p&gt;In addition, in the last semester I've been working daily with the AWS CDK (&lt;em&gt;Cloud Development Kit&lt;/em&gt;), an AWS tool that allows you to define infrastructure in the cloud using programming languages such as TypeScript. Compared to the years I worked with Terraform, which uses HCL (&lt;em&gt;HashiCorp Configuration Language&lt;/em&gt;), a specific declarative language for defining infrastructure as code, I can say that I've enjoyed using a conventional programming language to manage infrastructure much more than HCL.&lt;/p&gt;

&lt;p&gt;As such, Pulumi presented itself as a great option to use. It allows me to reuse my structure for TypeScript projects (as a linter, CI/CD, etc.), solves my infrastructure management problem and makes it possible to describe scenarios more dynamically than before (I believe one of the main advantages of using a programming language for this).&lt;/p&gt;

&lt;h2&gt;
  
  
  Considerations
&lt;/h2&gt;

&lt;p&gt;Before we go any further, I'd like to make a few considerations for this article:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You need to have Pulumi installed on your machine: &lt;a href="https://www.pulumi.com/docs/iac/download-install/" rel="noopener noreferrer"&gt;Download &amp;amp; install Pulumi&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;The programming language I will be using is TypeScript.&lt;/li&gt;
&lt;li&gt;The entire step-by-step will be done in an initially empty directory.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Preparing the project
&lt;/h2&gt;

&lt;p&gt;If you don't want to do the step-by-step in this section, you can use my template:&lt;/p&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/alvarofpp" rel="noopener noreferrer"&gt;
        alvarofpp
      &lt;/a&gt; / &lt;a href="https://github.com/alvarofpp/template-infra-pulumi" rel="noopener noreferrer"&gt;
        template-infra-pulumi
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Template for IaC projects using Pulumi.
    &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;Template for IaC using Pulumi&lt;/h1&gt;

&lt;/div&gt;
&lt;p&gt;This template comes with a structure for you to manage your personal
repositories or organizations on GitHub, as well as making it easy to expand to
other contexts.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Migrating GitHub resources to Pulumi&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;You can use the &lt;a href="https://github.com/alvarofpp/import-from-github-to-pulumi" rel="noopener noreferrer"&gt;alvarofpp/import-from-github-to-pulumi&lt;/a&gt; repository
to perform the migration of an organization or your personal repositories to
Pulumi.&lt;/p&gt;
&lt;/div&gt;



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


&lt;p&gt;Note that for each account there will be a directory with a TypeScript project, with its own &lt;code&gt;package.json&lt;/code&gt; files and the like. In my case, it will be a project for my personal repositories and a project for each organization. The step-by-step process for preparing the project is the same in all these cases.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating a project in Pulumi
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Use the local Pulumi login:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pulumi login file:&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;The &lt;code&gt;pulumi login&lt;/code&gt; command is used to authenticate your Pulumi CLI with a stateful storage backend. By default, you connect to the backend managed in the &lt;a href="//app.pulumi.com"&gt;Pulumi cloud&lt;/a&gt;. When we use &lt;code&gt;file:$(pwd)&lt;/code&gt;, you configure Pulumi to use a local file backend instead of the cloud backend.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Start a Pulumi project&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pulumi new typescript &lt;span class="nt"&gt;--force&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;We need to use &lt;code&gt;--force&lt;/code&gt; because the &lt;code&gt;login&lt;/code&gt; command will create a &lt;code&gt;home&lt;/code&gt; directory and the &lt;code&gt;new&lt;/code&gt; command requires to be run in an empty directory.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Install the GitHub provider:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @pulumi/github
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add the GitHub token:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pulumi config &lt;span class="nb"&gt;set &lt;/span&gt;github:token &amp;lt;token&amp;gt; &lt;span class="nt"&gt;--secret&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;If you don't know how to create an access token for the GitHub API, consult the official documentation: &lt;a href="https://docs.github.com/pt/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens" rel="noopener noreferrer"&gt;Managing your personal access tokens&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add the &lt;code&gt;owner&lt;/code&gt; (it can be a user or an organization):&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pulumi config &lt;span class="nb"&gt;set &lt;/span&gt;github:owner &amp;lt;owner&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

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

&lt;p&gt;By now your directory should be close to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.
├── Pulumi.main.yaml
├── Pulumi.yaml
├── index.ts
├── package-lock.json
├── package.json
└── tsconfig.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Making the project more dynamic
&lt;/h3&gt;

&lt;p&gt;As I'm going to have a lot of resources, it's not interesting to have to use a conventional import scheme, as it would mean always having to import a new repository when I create one, in addition to the more than 120 repositories I already have. Instead, I chose to dynamically import the resources.&lt;/p&gt;

&lt;p&gt;The aim is to have directories for each type of resource and a dynamic way of importing these resources.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Create a &lt;code&gt;registry.ts&lt;/code&gt; file with the following content:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;path&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;pulumi&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@pulumi/pulumi&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;RegistryBaseConstructor&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;new &lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;RegistryBase&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RegistryBase&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;suffix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;directory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;suffix&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;directory&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;ResourceRegistry&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;ResourceRegistry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;ResourceClass&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ResourceClass&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Critical error in init method: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;suffix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;directory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;anyResourceRegistry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;RegistryBaseConstructor&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;classesDir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;directory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readdirSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;classesDir&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;endsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;index.ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;suffix&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;modulePath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;classesDir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

          &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="kr"&gt;module&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;modulePath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Class&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;module&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
            &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Class&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="nx"&gt;anyResourceRegistry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Class&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Failed to register &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; class:`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;anyResourceRegistry&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;The &lt;code&gt;RegistryBase&lt;/code&gt; class will be our base class for the classes that will contain each type of resource. Its function is to be a registry of resources. The search for these resources will be dynamic, meeting two criteria:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The resources must have a previously defined suffix.&lt;/li&gt;
&lt;li&gt;The resources must be in the same directory as the registry.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create the &lt;code&gt;repositories&lt;/code&gt; directory:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;repositories
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create the file &lt;code&gt;repositories/index.ts&lt;/code&gt; with the following content:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;RegistryBase&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../registry&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RepositoriesRegistry&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;RegistryBase&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Repository&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;The &lt;code&gt;RepositoriesRegistry&lt;/code&gt; class will contain all the classes that have &lt;code&gt;Repository&lt;/code&gt; as a suffix and are inside &lt;code&gt;repositories/&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In the &lt;code&gt;index.ts&lt;/code&gt; file, import the &lt;code&gt;RepositoriesRegistry&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;RepositoriesRegistry&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./repositories&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;repositories&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;RepositoriesRegistry&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

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

&lt;blockquote&gt;
&lt;p&gt;❗ For the case of organizations, you must repeat steps 2 to 4 for &lt;code&gt;memberships&lt;/code&gt; (suffix &lt;code&gt;Membership&lt;/code&gt;) and &lt;code&gt;teams&lt;/code&gt; (suffix &lt;code&gt;Team&lt;/code&gt;).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So far your directory should look like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.
├── Pulumi.main.yaml
├── Pulumi.yaml
├── index.ts
├── memberships
│ └── index.ts
├── package-lock.json
├── package.json
├── repositories
│ └── index.ts
├── teams
│ └── index.ts
└── tsconfig.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Collecting data and generating resources in Pulumi
&lt;/h2&gt;

&lt;p&gt;We want the resources to be as faithful as possible to their current state, because if they are not, this could lead to an unwanted state update during import or use. To do this, we can use the GitHub API to collect the data for each resource and declare it in Pulumi.&lt;/p&gt;
&lt;h3&gt;
  
  
  Manual process
&lt;/h3&gt;

&lt;p&gt;Here you must create a script to collect the data from the GitHub API and assign it to Pulumi resources in the programming language of your choice.&lt;/p&gt;

&lt;p&gt;For repositories:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We have two ways of listing repositories:

&lt;ul&gt;
&lt;li&gt;For your personal repositories: &lt;code&gt;GET /user/repos?affiliation=owner&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;For an organization's repositories: &lt;code&gt;GET /orgs/&amp;lt;org&amp;gt;/repos&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Iterate over each repository and use the following endpoints to collect more detailed data:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;GET /repos/&amp;lt;user_or_org&amp;gt;/&amp;lt;repository_name&amp;gt;&lt;/code&gt;: for general data about the repository.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GET /repos/&amp;lt;repository_name&amp;gt;/pages&lt;/code&gt;: for data about the pages in the repository.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For members of an organization:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;GET /orgs/&amp;lt;org&amp;gt;/members&lt;/code&gt; to list the members of the organization.&lt;/li&gt;
&lt;li&gt;Iterate over each member and make a call to the &lt;code&gt;GET /orgs/&amp;lt;org&amp;gt;/memberships/&amp;lt;member&amp;gt;&lt;/code&gt; endpoint to collect data on that user's association with the organization.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For teams within an organization:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;GET /orgs/&amp;lt;org&amp;gt;/teams&lt;/code&gt; to list the organization's teams.&lt;/li&gt;
&lt;li&gt;Iterate over each team and use the following endpoints to collect more detailed data:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;GET /orgs/&amp;lt;org&amp;gt;/teams/&amp;lt;team&amp;gt;&lt;/code&gt; for general team data.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GET /orgs/&amp;lt;org&amp;gt;/teams/&amp;lt;team&amp;gt;/repos&lt;/code&gt; to list the team's repositories.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GET /orgs/&amp;lt;org&amp;gt;/teams/&amp;lt;team&amp;gt;/members&lt;/code&gt; to list the members of that team. Iterate on each member of the team:

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;GET /orgs/&amp;lt;org&amp;gt;/teams/&amp;lt;team&amp;gt;/memberships/&amp;lt;member&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now that you have all the data you need, just assign it to the respective resources in Pulumi:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Repository: &lt;a href="https://www.pulumi.com/registry/packages/github/api-docs/repository/" rel="noopener noreferrer"&gt;github.Repository&lt;/a&gt;.

&lt;ul&gt;
&lt;li&gt;Repository branch: &lt;a href="https://www.pulumi.com/registry/packages/github/api-docs/branch/" rel="noopener noreferrer"&gt;github.Branch&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Default branch (for unarchived repositories): &lt;a href="https://www.pulumi.com/registry/packages/github/api-docs/branchdefault/" rel="noopener noreferrer"&gt;github.BranchDefault&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Organization members: &lt;a href="https://www.pulumi.com/registry/packages/github/api-docs/membership/" rel="noopener noreferrer"&gt;github.Membership&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Teams in the organization: &lt;a href="https://www.pulumi.com/registry/packages/github/api-docs/team/" rel="noopener noreferrer"&gt;github.Team&lt;/a&gt;.

&lt;ul&gt;
&lt;li&gt;Team repositories: &lt;a href="https://www.pulumi.com/registry/packages/github/api-docs/teamrepository/" rel="noopener noreferrer"&gt;github.TeamRepository&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;For team members, you have two ways (I prefer the first because it's simpler):

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.pulumi.com/registry/packages/github/api-docs/teammembers/" rel="noopener noreferrer"&gt;github.TeamMembers&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.pulumi.com/registry/packages/github/api-docs/teammembership/" rel="noopener noreferrer"&gt;github.TeamMembership&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Importing using repository
&lt;/h3&gt;

&lt;p&gt;To abstract all this step-by-step data collection from GitHub and assembly of Pulumi resources that we saw earlier, I created the following repository:&lt;/p&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/alvarofpp" rel="noopener noreferrer"&gt;
        alvarofpp
      &lt;/a&gt; / &lt;a href="https://github.com/alvarofpp/import-from-github-to-pulumi" rel="noopener noreferrer"&gt;
        import-from-github-to-pulumi
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Scripts to import resources from organizations and personal projects on GitHub into Pulumi.
    &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;Import from GitHub to Pulumi&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;This repository contains a configured Docker image with scripts to import your personal
repositories or repositories, members and teams of an organization into Pulumi.&lt;/p&gt;
&lt;p&gt;After running the import script, two sets of artifacts are generated
and saved in the &lt;code&gt;resources/&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;import_*.txt&lt;/code&gt;: files with commands for importing resources.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;members/*.ts&lt;/code&gt;, &lt;code&gt;repositories/*.ts&lt;/code&gt; and &lt;code&gt;teams/*.ts&lt;/code&gt;: Pulumi resource files.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;a href="https://github.com/alvarofpp/template-infra-pulumi" rel="noopener noreferrer"&gt;alvarofpp/template-infra-pulumi&lt;/a&gt; repository has a directory structure
that you can use as a basis.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;How to use&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;This repository can be used for two purposes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Importing your personal repositories.&lt;/li&gt;
&lt;li&gt;Importing members of an organization's repositories and teams.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For both cases, you first need to run &lt;code&gt;make build&lt;/code&gt; to generate the
Docker image that will be used to run the scripts.&lt;/p&gt;
&lt;p&gt;The commands using &lt;code&gt;make&lt;/code&gt; that will be shown below can be found in the &lt;code&gt;Makefile&lt;/code&gt; file
If you choose not to use the &lt;a href="https://github.com/alvarofpp/import-from-github-to-pulumi/%60Makefile%60" rel="noopener noreferrer"&gt;Makefile&lt;/a&gt;, you can…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/alvarofpp/import-from-github-to-pulumi" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;In this repository, you will have a Docker image configured and with scripts to generate the resource files for Pulumi based on the data returned by the GitHub API.&lt;/p&gt;

&lt;p&gt;For this repository to work, you must have Docker and &lt;code&gt;make&lt;/code&gt; installed on your machine. If you use Linux, you probably already have &lt;code&gt;make&lt;/code&gt; installed.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ If you are importing accounts and organizations in sequence, after each import you can use the &lt;code&gt;make clear&lt;/code&gt; command to clear the logs and files generated during the previous import.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In another directory, clone the repository:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone git@github.com:alvarofpp/import-from-github-to-pulumi.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Generating personal repository files
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Export the access token to GitHub:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;GITHUB_ACCESS_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;github_pat_...
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Export your user on GitHub:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;GITHUB_USER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;...
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Run the command to generate the files for Pulumi:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;make import-my-repos
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;In the &lt;code&gt;resources&lt;/code&gt; directory you will find the following files:&lt;br&gt;
    - &lt;code&gt;import_*.txt&lt;/code&gt;: file with the import commands.&lt;br&gt;
    - &lt;code&gt;repositories/*.ts&lt;/code&gt;: files with the resources for each repository.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Generating the files of repositories, members and teams of an organization
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Export the access token to GitHub:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;GITHUB_ACCESS_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;github_pat_...
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Export the name of the organization on GitHub:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;GITHUB_ORG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;...
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Run the command to generate the files for Pulumi:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;make import-org
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;In the &lt;code&gt;resources&lt;/code&gt; directory you will find the following files:&lt;br&gt;
    - &lt;code&gt;import_*.txt&lt;/code&gt;: file with the import commands.&lt;br&gt;
    - &lt;code&gt;memberships/*.ts&lt;/code&gt;: files for each member of the organization.&lt;br&gt;
    - &lt;code&gt;repositories/*.ts&lt;/code&gt;: files for each repository in the organization.&lt;br&gt;
    - &lt;code&gt;teams/*.ts&lt;/code&gt;: files for each team in the organization.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Importing resources
&lt;/h2&gt;

&lt;p&gt;If you have collected the data yourself, then you should also set up the import commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Repository&lt;/span&gt;
pulumi import github:index/repository:Repository &amp;lt;resource_name&amp;gt; &amp;lt;repository&amp;gt;

&lt;span class="c"&gt;# Branch of the repository&lt;/span&gt;
pulumi import github:index/branch:Branch &amp;lt;resource_name&amp;gt; &amp;lt;repository&amp;gt;:&amp;lt;branch&amp;gt;

&lt;span class="c"&gt;# Organization member&lt;/span&gt;
pulumi import github:index/membership:Membership &amp;lt;resource_name&amp;gt; &amp;lt;org&amp;gt;:&amp;lt;member&amp;gt;

&lt;span class="c"&gt;# Organization team&lt;/span&gt;
pulumi import github:index/team:Team &amp;lt;resource_name&amp;gt; &amp;lt;team_id&amp;gt;

&lt;span class="c"&gt;# Team members&lt;/span&gt;
pulumi import github:index/teamMembers:TeamMembers &amp;lt;resource_name&amp;gt; &amp;lt;team_id&amp;gt;

&lt;span class="c"&gt;# Team repository&lt;/span&gt;
pulumi import github:index/teamRepository:TeamRepository &amp;lt;resource_name&amp;gt; &amp;lt;team_id&amp;gt;:&amp;lt;repository&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you have chosen to use the repository I suggested earlier, the step by step is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Copy the &lt;code&gt;*.ts&lt;/code&gt; files to their respective directories in the Pulumi project.&lt;/li&gt;
&lt;li&gt;Execute all the commands in the &lt;code&gt;import_*.txt&lt;/code&gt; files.&lt;/li&gt;
&lt;li&gt;Now run &lt;code&gt;pulumi up&lt;/code&gt; and apply the updates, if any.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That's it, you now have a project that allows you to manage your GitHub resources using Pulumi. Remember that this structure can be expanded to other types of resources and that you are using a programming language for this, so scripted automations work very well in this context.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hints and tips
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Note that we use the local Pulumi login, this is just to make it easier to teach. In a real environment, it is preferable that you save the states in S3 or a similar service.&lt;/li&gt;
&lt;li&gt;The indentation of the codes may not be properly aligned, but you can use a formatter/linter to fix this. In my case, I use Deno's (&lt;code&gt;deno fmt&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Use cases
&lt;/h2&gt;

&lt;p&gt;There are several use cases and it depends on your context or the context of the organization. Here I'll list just a few use cases that are mainly useful for personal accounts.&lt;/p&gt;

&lt;h3&gt;
  
  
  Updating specific files
&lt;/h3&gt;

&lt;p&gt;With the &lt;code&gt;RepositoryFile&lt;/code&gt; feature you can manage specific files in your repositories. Examples of interesting files to use this feature are &lt;code&gt;LICENSE&lt;/code&gt; and also workflows. This last type of file (workflows) is very useful for personal accounts, as GitHub allows you to share actions and workflows in organizations, but not in personal accounts.&lt;/p&gt;

&lt;h3&gt;
  
  
  Updating repositories for special occasions
&lt;/h3&gt;

&lt;p&gt;I have some repositories that participate in Hacktoberfest. So I intend to put a date check so that every beginning of October I add the &lt;code&gt;hacktoberfest&lt;/code&gt; topic to the repository and every beginning of November I remove that topic.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sharing and access management
&lt;/h3&gt;

&lt;p&gt;Now it's easier to define which accounts are part of your organization, their privileges, which teams have access to which repositories, etc.&lt;/p&gt;

&lt;h3&gt;
  
  
  Management of variables and secrets
&lt;/h3&gt;

&lt;p&gt;If you use GitHub Actions, you should be familiar with the use of variables and secrets in your workflows. A good practice is to put a short expiration time on secrets and renew them whenever possible. Pulumi allows you to store secrets in the stack, the command to insert the GitHub token into the project is an example of this, so you can integrate this functionality with a token renewal script. Every time the script is run, it automatically updates the token in the stack and updates the secret in the repository.&lt;/p&gt;

</description>
      <category>github</category>
      <category>pulumi</category>
      <category>iac</category>
      <category>howto</category>
    </item>
  </channel>
</rss>
