{"author_link":"\/users\/sean-esopenko","author_name":"Sean Esopenko","author_uid":"sean-esopenko","comments":[],"epoch":1664858375,"event":"LD51","format":"md","ldjam_node_id":308006,"likes":17,"metadata":{"p_key":"168368","p_author":"Sean Esopenko","p_authorkey":"1298673","p_urlkey":"396125","p_title":"We released Clique Hell High 112 times and this is how we did it...","p_cat":"LDJam ","p_event":"LD51","p_time":"1664858375","p_likes":"17","p_comments":"0","p_status":"WAYBACK","us_key":"1298673","us_name":"Sean Esopenko","us_username":"sean-esopenko","event_start":"1664496000","event_key":"114","event_name":"Ludum Dare 51"},"node":{"_collation":{"body_sanitizer":"TextUtils::SanitizeHTML via existing importer","event":"LD51","removed_author":false},"_superparent":296586,"_trust":2,"author":298673,"body":"[![IMAGE ALT TEXT HERE](https:\/\/img.youtube.com\/vi\/boNosPiygPY\/0.jpg)](https:\/\/www.youtube.com\/watch?v=boNosPiygPY)\n*Let's Play recording by [100th_coin](https:\/\/ldjam.com\/users\/100th-coin\/games) of [Clique Hell High](https:\/\/ldjam.com\/events\/ludum-dare\/51\/clique-hell-high), which was released 112 times*\n\nShipping software is stressful and getting your game delivered and playable during the zero hour of Ludum Dare is even more stressful. There are so many places where the delivery process can go wrong and doing it by hand makes that process fragile. With only 48-72 hours to make a game, every time 5-20 minutes is spent packaging up a game and deploying to itch.io is taking precious time away from development of a game. However, the feedback is critical throughout the development process, so what is one to do?  Well, we shipped [Clique Hell High](https:\/\/ldjam.com\/events\/ludum-dare\/51\/clique-hell-high) 112 times since Friday afternoon, and none of us had to step away from any of our tasks at hand.  How did we do it?  We used Github Actions to build an automated continuous delivery pipeline: every time we tagged a release, automated tooling exported our game, packaged it up, and uploaded it to itch.io. Here are the details on how we did it.\n\nTools used:\n\n* [Godot](https:\/\/godotengine.org\/)\n* [Github](https:\/\/github.com\/)\n* [Github Desktop](https:\/\/desktop.github.com\/)\n* [Github Actions](https:\/\/github.com\/features\/actions)\n\n[![godot.png](\/\/\/raw\/1be\/84\/z\/51d69.png)](https:\/\/godotengine.org\/)\n\nThe first step in the pipeline was our actual IDE\/Engine.  Looking over the landscape of game engines, [Godot](https:\/\/godotengine.org\/) was the best featured with all the tooling required to set it up in a CICD pipeline.  If you haven't used Godot, give it a look, because while scenes inside scenes is the killer app of Godot, overall it's a great game engine\/editor for small projects like game jam. It's the perfect engine for small game projects.\n\nGodot lets you place [scenes inside scenes](https:\/\/docs.godotengine.org\/en\/3.6\/getting_started\/step_by_step\/nodes_and_scenes.html) as nodes, and if your team agrees to only one team member editing a scene at a time, you still have a lot of opportunities to synergize and work on the same systems together. One person works on arranging the level in one scene, and is the only person who's allowed to make changes in Git for it. How do the rest of the team members contribute to the level simultaneously? With scenes as instances.  Towards the end of the project we would have one team member working on the mechanics for the exit door in its own scene, while another arranged the enemies in the main map.  Nobody had merge conflicts thanks to scenes within scenes in godot.\n\n![git_tags_screenshot.png](\/\/\/raw\/1be\/84\/z\/51d1d.png)\n*112 git versions, each one published automatically to itch.io*\n\nDuring the first hour, we had a rough level that the player could wander in and the rest of our team who weren't developers were able to play it on itch.io, with each iteration released hourly.  Practically with every change of our code base, our pipeline shipped a new version to itch.io.\n\n[![GitHub-logo.png](\/\/\/raw\/1be\/84\/z\/51d78.png)](https:\/\/github.com\/)\n\n\n\nThe next component was our version control system and merging our work together, integrating it, as frequently as possible, multiple times per hour.  To do this, we used git, backed by github. Every team member actively working with the Godot editor had a copy of [Github Desktop](https:\/\/desktop.github.com\/), and a github account with access to the private project repository. Every hour, each contributor committed their work to github and merged it together. This meant everybody who was dependant on everyone else got to see if their work stepped on the toes of others right away.  Our play testers on the team could spot problems with integrated systems quickly.\n\n![github_desktop.png](\/\/\/raw\/1be\/84\/z\/51d21.png)\n*[Github Desktop](https:\/\/desktop.github.com\/) makes it possible to snapshot your work and integrate with other contributors on the team*\n\nCompared to a network drive, a version control system like git lets our team snapshot their local changes (undo on steroids) while integrating together upstream and test their integrated changes together.\n\nDelivery pipelines have been around for a while but they used to be the domain of large corporations: clunky jenkins servers packaging up code bases maintained by hundreds of developers, with the automated systems being babied like precious, cantankerous animals. Over the past decade, these automated systems have become easier to set up with bot Bitbucket and Github offering completely free, easy to use solutions.\n\n\n![export_stage.png](\/\/\/raw\/1be\/84\/z\/51d28.png)\n*export stage of our pipeline*\n\nNow that we have our code integrated, how did we package it up?  The solution was Github Actions, particularly the [firebelly\/godot-export](https:\/\/github.com\/firebelley\/godot-export) github action. With a `.github\/workflows\/main.yml` file using the documented YAML code from the export action, every time we tagged a release, the github action packaged the godot export up into zip files.  Instead of requiring a team member to manually export the project to their local computer, the pipeline did this for us.  You don't even have to use github, because other providers offer similar solutions, all of them with free tiers:\n\n* [Github Actions](https:\/\/github.com\/features\/actions)\n* [Gitlab CI\/CD Pipelines](https:\/\/docs.gitlab.com\/ee\/ci\/pipelines\/)\n* [Bitbucket Pipelines](https:\/\/bitbucket.org\/product\/features\/pipelines)\n* [AWS Code Build](https:\/\/aws.amazon.com\/codebuild\/)\n* [Azure Pipelines](https:\/\/azure.microsoft.com\/fr-ca\/blog\/azure-pipelines-is-the-ci-cd-solution-for-any-language-any-platform-any-cloud\/)\n\nAdd an action for exporting the game in your pipeline. Here's a snippet of the yaml we used to export our Godot project automatically:\n\n```yaml\n    - name: export game\n      id: export\n      # Use latest version (see releases for all versions)\n      uses: firebelley\/godot-export@v4.1.1\n      with:\n        # Defining all the required inputs\n        godot_executable_download_url: https:\/\/github.com\/godotengine\/godot\/releases\/download\/3.4.4-stable\/Godot_v3.4.4-stable_linux_headless.64.zip\n        godot_export_templates_download_url: https:\/\/github.com\/godotengine\/godot\/releases\/download\/3.4.4-stable\/Godot_v3.4.4-stable_export_templates.tpz\n        relative_project_path: .\/\n        archive_output: true\n```\n\n*YAML code snippet of the export stage of our github action *\n\nAnd here's the log output of the files being zipped up:\n\n```\n\n\u2692\ufe0f Zipping binaries\n  \/usr\/bin\/7z a \/home\/runner\/.local\/share\/godot\/archives\/webgl.zip \/home\/runner\/.local\/share\/godot\/builds\/webgl\/*\n  \/usr\/bin\/7z a \/home\/runner\/.local\/share\/godot\/archives\/win.zip \/home\/runner\/.local\/share\/godot\/builds\/win\/*\n  \n  7-Zip [64] 16.02 : Copyright (c) 1999-2016 Igor Pavlov : 2016-05-21\n  p7zip Version 16.02 (locale=C.UTF-8,Utf16=on,HugeFiles=on,64 bits,2 CPUs Intel(R) Xeon(R) Platinum 8171M CPU @ 2.60GHz (50654),ASM,AES-NI)\n  \n  Scanning the drive:\n  2 files, 191255312 bytes (183 MiB)\n  \n  Creating archive: \/home\/runner\/.local\/share\/godot\/archives\/win.zip\n  \n  Items to compress: 2\n  \n  \n  Files read from disk: 2\n  Archive size: 37712907 bytes (36 MiB)\n  Everything is Ok\n  \n  7-Zip [64] 16.02 : Copyright (c) 1999-2016 Igor Pavlov : 2016-05-21\n  p7zip Version 16.02 (locale=C.UTF-8,Utf16=on,HugeFiles=on,64 bits,2 CPUs Intel(R) Xeon(R) Platinum 8171M CPU @ 2.60GHz (50654),ASM,AES-NI)\n  \n  Scanning the drive:\n  9 files, 174647145 bytes (167 MiB)\n  \n  Creating archive: \/home\/runner\/.local\/share\/godot\/archives\/webgl.zip\n  \n  Items to compress: 9\n  \n  \n  Files read from disk: 9\n  Archive size: 28699214 bytes (28 MiB)\n  Everything is Ok\n```\n\n*Output of the zipping sub-stage of our export stage*\n\nSo what happens here?  Well, to be honest, without any other work the zip files would fall into the ether, into a black hole, without any means of using them. The resulting files are saved as *artifacts* in the pipeline, available for download in github by any team members with access to the github repository.  This got us part of the way there.\n\n![artifacts.png](\/\/\/raw\/1be\/84\/z\/51d2c.png)\n*web HTML5 and windows exe artifacts automatically produced by our pipeline *\n\nThese artifacts are saved in the github repository, one batch of artifacts for each version for archival purposes, using the following snippet:\n\n```yaml\n    - name: upload windows artifact\n      id: upload_win_artifact\n      uses: actions\/upload-artifact@v3\n      with:\n        name: ${{ steps.tag_version.outputs.TAG_VERSION }}-win\n        path: ${{ steps.export.outputs.archive_directory }}\/win.zip\n    - name: upload webgl artifact\n      id: upload_webgl_artifact\n      uses: actions\/upload-artifact@v3\n      with:\n        name: ${{ steps.tag_version.outputs.TAG_VERSION }}-webgl\n        path: ${{ steps.export.outputs.archive_directory }}\/webgl.zip\n```\n\n*artifact uploading YAML snippet *\n\nThe next step in our pipeline is the juicy bit: uploading the zip files automatically to itch.io. This took a few steps to set up, with the first one being getting an authentication token for itch.io's  upload program, [Butler](https:\/\/github.com\/itchio\/butler). I had to download butler for my windows PC, then use butler to log into the system. [Detailed instructions for logging into butler for your pipeline are here.](https:\/\/itch.io\/docs\/butler\/login.html#running-butler-from-ci-builds-travis-ci-gitlab-ci-etc)\n\n![butler-login.png](\/\/\/raw\/1be\/84\/z\/51d31.png)\n*butler login prompt *\n\nIf you think it's a good idea to put this API key right in your repository, think again. If your repository were compromised somebody would be able to make api calls to itch.io as though they are you, and could do nefarious things in your name, such as try to DDOS itch.io during the game jam. Github has a Secrets system to store secrets securely with one-way entering: once you enter it a human can't get it back out. After logging in, the secret api key is set up using [Github Action Secrets](https:\/\/www.theserverside.com\/blog\/Coffee-Talk-Java-News-Stories-and-Opinions\/GitHub-Actions-Secrets-Example-Token-Tutorial).\n\n![github secrets.png](\/\/\/raw\/1be\/84\/z\/51d32.png)\n*The secrets we had set up for our pipeline. not even I can read them now. *\n\nNow that our secrets were set up, we used the following snippet to upload our artifacts to itch.io automatically:\n\n```yaml\n    - name: download-artifact-win\n      id: artifact_win_download\n      uses: actions\/download-artifact@v2.0.8\n      with:\n        name: ${{ steps.tag_version.outputs.TAG_VERSION }}-win\n        path: build\/win\n    - name: list artifact\n      id: list_artifact\n      run: ls -lha .\/build\/win\n    - name: push windows to itch\n      id: itch_win_push\n      uses: KikimoraGames\/itch-publish@v0.0.3\n      with:\n        butlerApiKey: ${{secrets.BUTLER_API_KEY}}\n        gameData: .\/build\/win\/win.zip\n        itchUsername: ${{secrets.ITCH_USERNAME}}\n        itchGameId: ${{ secrets.ITCH_GAME_ID }}\n        buildChannel: windows\n        buildNumber: ${{ steps.tag_version.outputs.TAG_VERSION }}\n    - name: download-artifact-webgl\n      id: artifact_webgl_download\n      uses: actions\/download-artifact@v2.0.8\n      with:\n        name: ${{ steps.tag_version.outputs.TAG_VERSION }}-webgl\n        path: build\/webgl\n    - name: push webgl to itch\n      id: itch_webgl_push\n      uses: KikimoraGames\/itch-publish@v0.0.3\n      with:\n        butlerApiKey: ${{secrets.BUTLER_API_KEY}}\n        gameData: .\/build\/webgl\/webgl.zip\n        itchUsername: ${{secrets.ITCH_USERNAME}}\n        itchGameId: ${{ secrets.ITCH_GAME_ID }}\n        buildChannel: webgl\n        buildNumber: ${{ steps.tag_version.outputs.TAG_VERSION }}\n```\n*push to itch stages of our pipeline*\n\nFor the windows and html5 exports each, it downloads the packaged artifact then used [KikimoraGames\/itch-publish](https:\/\/github.com\/KikimoraGames\/itch-publish) to automatically publish the zip files to itch.io.  We're almost there.\n\nAs-is, the uploads aren't ready for consumption and the itch.io page needed some configuration for the file downloads. The html5 download had to be configured as an HTML5 download in order for it to appear in a player on the page. With this step done, every time we tagged a commit and pushed the tags, our itch.io page was updated minutes later  We could ask our friends and play testers to test our game in progress and they could provide feedback.\n\n![itch_upload_dialog.png](\/\/\/raw\/1be\/84\/z\/51d36.png)\n*our file configuratons for our automatically uploaded artifacts *\n\nIn the end, we tagged our repository 112 times since friday afternoon, which resulted in 112 releases. We were confident that we could ship the game 20 minutes before the cut-off because we had done it 112 times already, and knew exactly how long the pipeline would take.  We even snuck in an extra release with some minor tweaks for good measure with 44 seconds to go and hit our publish button on the submission.\n\n![pipeline-runs.png](\/\/\/raw\/1be\/84\/z\/51d37.png)\n* multiple releases per hour means feedback multiple times per hour *\n\nNobody on our team had made a game before with this many people and having this tooling to continually integrate our work, and continually test it, then continually package it up, let us work together with confidence. It's free to use, with thousands of free pipeline minutes included with github and 500mb of free storage.\n\nNext game jam, get immediate feedback by setting up your own pipeline and leave the stress of packaging behind.  Focus on your deliverables and not your delivery.  I hope this is helpful for others at the next jam and if you have questions feel free to leave them on the post.","comments":5,"comments-timestamp":"2022-10-07T06:10:21Z","created":"2022-10-04T03:54:08Z","files":[],"files-timestamp":0,"id":308006,"love":17,"love-timestamp":"2022-10-05T05:49:49Z","meta":[],"modified":"2022-10-07T06:10:21Z","name":"We released Clique Hell High 112 times and this is how we did it...","node-timestamp":"2022-10-04T06:24:31Z","parent":300633,"parents":[1,5,9,296586,300633],"path":"\/events\/ludum-dare\/51\/clique-hell-high\/we-released-clique-hell-high-112-times-and-this-is-how-we-did-it","published":"2022-10-04T04:39:35Z","scope":"public","slug":"we-released-clique-hell-high-112-times-and-this-is-how-we-did-it","subsubtype":"","subtype":"","type":"post","version":956907},"node_metadata":{"n_key":"308006","n_urlkey":"396125","n_parent":"300633","n_path":"\/events\/ludum-dare\/51\/clique-hell-high\/we-released-clique-hell-high-112-times-and-this-is-how-we-did-it","n_slug":"we-released-clique-hell-high-112","n_type":"post","n_subtype":"","n_subsubtype":"","n_author":"298673","n_created":"1664855648","n_modified":"1665123021","n_version":"956907","n_status":"WAYBACK"},"source_url":"https:\/\/ldjam.com\/events\/ludum-dare\/51\/clique-hell-high\/we-released-clique-hell-high-112-times-and-this-is-how-we-did-it","text":"[![IMAGE ALT TEXT HERE](https:\/\/img.youtube.com\/vi\/boNosPiygPY\/0.jpg)](https:\/\/www.youtube.com\/watch?v=boNosPiygPY)\n*Let's Play recording by [100th_coin](https:\/\/ldjam.com\/users\/100th-coin\/games) of [Clique Hell High](https:\/\/ldjam.com\/events\/ludum-dare\/51\/clique-hell-high), which was released 112 times*\n\nShipping software is stressful and getting your game delivered and playable during the zero hour of Ludum Dare is even more stressful. There are so many places where the delivery process can go wrong and doing it by hand makes that process fragile. With only 48-72 hours to make a game, every time 5-20 minutes is spent packaging up a game and deploying to itch.io is taking precious time away from development of a game. However, the feedback is critical throughout the development process, so what is one to do?  Well, we shipped [Clique Hell High](https:\/\/ldjam.com\/events\/ludum-dare\/51\/clique-hell-high) 112 times since Friday afternoon, and none of us had to step away from any of our tasks at hand.  How did we do it?  We used Github Actions to build an automated continuous delivery pipeline: every time we tagged a release, automated tooling exported our game, packaged it up, and uploaded it to itch.io. Here are the details on how we did it.\n\nTools used:\n\n* [Godot](https:\/\/godotengine.org\/)\n* [Github](https:\/\/github.com\/)\n* [Github Desktop](https:\/\/desktop.github.com\/)\n* [Github Actions](https:\/\/github.com\/features\/actions)\n\n[![godot.png](\/\/\/raw\/1be\/84\/z\/51d69.png)](https:\/\/godotengine.org\/)\n\nThe first step in the pipeline was our actual IDE\/Engine.  Looking over the landscape of game engines, [Godot](https:\/\/godotengine.org\/) was the best featured with all the tooling required to set it up in a CICD pipeline.  If you haven't used Godot, give it a look, because while scenes inside scenes is the killer app of Godot, overall it's a great game engine\/editor for small projects like game jam. It's the perfect engine for small game projects.\n\nGodot lets you place [scenes inside scenes](https:\/\/docs.godotengine.org\/en\/3.6\/getting_started\/step_by_step\/nodes_and_scenes.html) as nodes, and if your team agrees to only one team member editing a scene at a time, you still have a lot of opportunities to synergize and work on the same systems together. One person works on arranging the level in one scene, and is the only person who's allowed to make changes in Git for it. How do the rest of the team members contribute to the level simultaneously? With scenes as instances.  Towards the end of the project we would have one team member working on the mechanics for the exit door in its own scene, while another arranged the enemies in the main map.  Nobody had merge conflicts thanks to scenes within scenes in godot.\n\n![git_tags_screenshot.png](\/\/\/raw\/1be\/84\/z\/51d1d.png)\n*112 git versions, each one published automatically to itch.io*\n\nDuring the first hour, we had a rough level that the player could wander in and the rest of our team who weren't developers were able to play it on itch.io, with each iteration released hourly.  Practically with every change of our code base, our pipeline shipped a new version to itch.io.\n\n[![GitHub-logo.png](\/\/\/raw\/1be\/84\/z\/51d78.png)](https:\/\/github.com\/)\n\n\n\nThe next component was our version control system and merging our work together, integrating it, as frequently as possible, multiple times per hour.  To do this, we used git, backed by github. Every team member actively working with the Godot editor had a copy of [Github Desktop](https:\/\/desktop.github.com\/), and a github account with access to the private project repository. Every hour, each contributor committed their work to github and merged it together. This meant everybody who was dependant on everyone else got to see if their work stepped on the toes of others right away.  Our play testers on the team could spot problems with integrated systems quickly.\n\n![github_desktop.png](\/\/\/raw\/1be\/84\/z\/51d21.png)\n*[Github Desktop](https:\/\/desktop.github.com\/) makes it possible to snapshot your work and integrate with other contributors on the team*\n\nCompared to a network drive, a version control system like git lets our team snapshot their local changes (undo on steroids) while integrating together upstream and test their integrated changes together.\n\nDelivery pipelines have been around for a while but they used to be the domain of large corporations: clunky jenkins servers packaging up code bases maintained by hundreds of developers, with the automated systems being babied like precious, cantankerous animals. Over the past decade, these automated systems have become easier to set up with bot Bitbucket and Github offering completely free, easy to use solutions.\n\n\n![export_stage.png](\/\/\/raw\/1be\/84\/z\/51d28.png)\n*export stage of our pipeline*\n\nNow that we have our code integrated, how did we package it up?  The solution was Github Actions, particularly the [firebelly\/godot-export](https:\/\/github.com\/firebelley\/godot-export) github action. With a `.github\/workflows\/main.yml` file using the documented YAML code from the export action, every time we tagged a release, the github action packaged the godot export up into zip files.  Instead of requiring a team member to manually export the project to their local computer, the pipeline did this for us.  You don't even have to use github, because other providers offer similar solutions, all of them with free tiers:\n\n* [Github Actions](https:\/\/github.com\/features\/actions)\n* [Gitlab CI\/CD Pipelines](https:\/\/docs.gitlab.com\/ee\/ci\/pipelines\/)\n* [Bitbucket Pipelines](https:\/\/bitbucket.org\/product\/features\/pipelines)\n* [AWS Code Build](https:\/\/aws.amazon.com\/codebuild\/)\n* [Azure Pipelines](https:\/\/azure.microsoft.com\/fr-ca\/blog\/azure-pipelines-is-the-ci-cd-solution-for-any-language-any-platform-any-cloud\/)\n\nAdd an action for exporting the game in your pipeline. Here's a snippet of the yaml we used to export our Godot project automatically:\n\n```yaml\n    - name: export game\n      id: export\n      # Use latest version (see releases for all versions)\n      uses: firebelley\/godot-export@v4.1.1\n      with:\n        # Defining all the required inputs\n        godot_executable_download_url: https:\/\/github.com\/godotengine\/godot\/releases\/download\/3.4.4-stable\/Godot_v3.4.4-stable_linux_headless.64.zip\n        godot_export_templates_download_url: https:\/\/github.com\/godotengine\/godot\/releases\/download\/3.4.4-stable\/Godot_v3.4.4-stable_export_templates.tpz\n        relative_project_path: .\/\n        archive_output: true\n```\n\n*YAML code snippet of the export stage of our github action *\n\nAnd here's the log output of the files being zipped up:\n\n```\n\n\u2692\ufe0f Zipping binaries\n  \/usr\/bin\/7z a \/home\/runner\/.local\/share\/godot\/archives\/webgl.zip \/home\/runner\/.local\/share\/godot\/builds\/webgl\/*\n  \/usr\/bin\/7z a \/home\/runner\/.local\/share\/godot\/archives\/win.zip \/home\/runner\/.local\/share\/godot\/builds\/win\/*\n  \n  7-Zip [64] 16.02 : Copyright (c) 1999-2016 Igor Pavlov : 2016-05-21\n  p7zip Version 16.02 (locale=C.UTF-8,Utf16=on,HugeFiles=on,64 bits,2 CPUs Intel(R) Xeon(R) Platinum 8171M CPU @ 2.60GHz (50654),ASM,AES-NI)\n  \n  Scanning the drive:\n  2 files, 191255312 bytes (183 MiB)\n  \n  Creating archive: \/home\/runner\/.local\/share\/godot\/archives\/win.zip\n  \n  Items to compress: 2\n  \n  \n  Files read from disk: 2\n  Archive size: 37712907 bytes (36 MiB)\n  Everything is Ok\n  \n  7-Zip [64] 16.02 : Copyright (c) 1999-2016 Igor Pavlov : 2016-05-21\n  p7zip Version 16.02 (locale=C.UTF-8,Utf16=on,HugeFiles=on,64 bits,2 CPUs Intel(R) Xeon(R) Platinum 8171M CPU @ 2.60GHz (50654),ASM,AES-NI)\n  \n  Scanning the drive:\n  9 files, 174647145 bytes (167 MiB)\n  \n  Creating archive: \/home\/runner\/.local\/share\/godot\/archives\/webgl.zip\n  \n  Items to compress: 9\n  \n  \n  Files read from disk: 9\n  Archive size: 28699214 bytes (28 MiB)\n  Everything is Ok\n```\n\n*Output of the zipping sub-stage of our export stage*\n\nSo what happens here?  Well, to be honest, without any other work the zip files would fall into the ether, into a black hole, without any means of using them. The resulting files are saved as *artifacts* in the pipeline, available for download in github by any team members with access to the github repository.  This got us part of the way there.\n\n![artifacts.png](\/\/\/raw\/1be\/84\/z\/51d2c.png)\n*web HTML5 and windows exe artifacts automatically produced by our pipeline *\n\nThese artifacts are saved in the github repository, one batch of artifacts for each version for archival purposes, using the following snippet:\n\n```yaml\n    - name: upload windows artifact\n      id: upload_win_artifact\n      uses: actions\/upload-artifact@v3\n      with:\n        name: ${{ steps.tag_version.outputs.TAG_VERSION }}-win\n        path: ${{ steps.export.outputs.archive_directory }}\/win.zip\n    - name: upload webgl artifact\n      id: upload_webgl_artifact\n      uses: actions\/upload-artifact@v3\n      with:\n        name: ${{ steps.tag_version.outputs.TAG_VERSION }}-webgl\n        path: ${{ steps.export.outputs.archive_directory }}\/webgl.zip\n```\n\n*artifact uploading YAML snippet *\n\nThe next step in our pipeline is the juicy bit: uploading the zip files automatically to itch.io. This took a few steps to set up, with the first one being getting an authentication token for itch.io's  upload program, [Butler](https:\/\/github.com\/itchio\/butler). I had to download butler for my windows PC, then use butler to log into the system. [Detailed instructions for logging into butler for your pipeline are here.](https:\/\/itch.io\/docs\/butler\/login.html#running-butler-from-ci-builds-travis-ci-gitlab-ci-etc)\n\n![butler-login.png](\/\/\/raw\/1be\/84\/z\/51d31.png)\n*butler login prompt *\n\nIf you think it's a good idea to put this API key right in your repository, think again. If your repository were compromised somebody would be able to make api calls to itch.io as though they are you, and could do nefarious things in your name, such as try to DDOS itch.io during the game jam. Github has a Secrets system to store secrets securely with one-way entering: once you enter it a human can't get it back out. After logging in, the secret api key is set up using [Github Action Secrets](https:\/\/www.theserverside.com\/blog\/Coffee-Talk-Java-News-Stories-and-Opinions\/GitHub-Actions-Secrets-Example-Token-Tutorial).\n\n![github secrets.png](\/\/\/raw\/1be\/84\/z\/51d32.png)\n*The secrets we had set up for our pipeline. not even I can read them now. *\n\nNow that our secrets were set up, we used the following snippet to upload our artifacts to itch.io automatically:\n\n```yaml\n    - name: download-artifact-win\n      id: artifact_win_download\n      uses: actions\/download-artifact@v2.0.8\n      with:\n        name: ${{ steps.tag_version.outputs.TAG_VERSION }}-win\n        path: build\/win\n    - name: list artifact\n      id: list_artifact\n      run: ls -lha .\/build\/win\n    - name: push windows to itch\n      id: itch_win_push\n      uses: KikimoraGames\/itch-publish@v0.0.3\n      with:\n        butlerApiKey: ${{secrets.BUTLER_API_KEY}}\n        gameData: .\/build\/win\/win.zip\n        itchUsername: ${{secrets.ITCH_USERNAME}}\n        itchGameId: ${{ secrets.ITCH_GAME_ID }}\n        buildChannel: windows\n        buildNumber: ${{ steps.tag_version.outputs.TAG_VERSION }}\n    - name: download-artifact-webgl\n      id: artifact_webgl_download\n      uses: actions\/download-artifact@v2.0.8\n      with:\n        name: ${{ steps.tag_version.outputs.TAG_VERSION }}-webgl\n        path: build\/webgl\n    - name: push webgl to itch\n      id: itch_webgl_push\n      uses: KikimoraGames\/itch-publish@v0.0.3\n      with:\n        butlerApiKey: ${{secrets.BUTLER_API_KEY}}\n        gameData: .\/build\/webgl\/webgl.zip\n        itchUsername: ${{secrets.ITCH_USERNAME}}\n        itchGameId: ${{ secrets.ITCH_GAME_ID }}\n        buildChannel: webgl\n        buildNumber: ${{ steps.tag_version.outputs.TAG_VERSION }}\n```\n*push to itch stages of our pipeline*\n\nFor the windows and html5 exports each, it downloads the packaged artifact then used [KikimoraGames\/itch-publish](https:\/\/github.com\/KikimoraGames\/itch-publish) to automatically publish the zip files to itch.io.  We're almost there.\n\nAs-is, the uploads aren't ready for consumption and the itch.io page needed some configuration for the file downloads. The html5 download had to be configured as an HTML5 download in order for it to appear in a player on the page. With this step done, every time we tagged a commit and pushed the tags, our itch.io page was updated minutes later  We could ask our friends and play testers to test our game in progress and they could provide feedback.\n\n![itch_upload_dialog.png](\/\/\/raw\/1be\/84\/z\/51d36.png)\n*our file configuratons for our automatically uploaded artifacts *\n\nIn the end, we tagged our repository 112 times since friday afternoon, which resulted in 112 releases. We were confident that we could ship the game 20 minutes before the cut-off because we had done it 112 times already, and knew exactly how long the pipeline would take.  We even snuck in an extra release with some minor tweaks for good measure with 44 seconds to go and hit our publish button on the submission.\n\n![pipeline-runs.png](\/\/\/raw\/1be\/84\/z\/51d37.png)\n* multiple releases per hour means feedback multiple times per hour *\n\nNobody on our team had made a game before with this many people and having this tooling to continually integrate our work, and continually test it, then continually package it up, let us work together with confidence. It's free to use, with thousands of free pipeline minutes included with github and 500mb of free storage.\n\nNext game jam, get immediate feedback by setting up your own pipeline and leave the stress of packaging behind.  Focus on your deliverables and not your delivery.  I hope this is helpful for others at the next jam and if you have questions feel free to leave them on the post.","title":"We released Clique Hell High 112 times and this is how we did it...","wayback_source":[]}