├── icon.png ├── addons └── github_to_itch │ ├── assets │ ├── secrets.png │ └── secrets.png.import │ ├── plugin.cfg │ ├── popup.tscn │ ├── LICENSE │ ├── ui │ ├── config.gd │ ├── info_bubble.tscn │ └── config.tscn │ ├── tempaltes │ ├── notify_job.yml │ └── workflow_template.yml │ ├── plugin.gd │ └── templates.gd ├── LICENSE └── README.md /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MeagherGames/github_to_itch/HEAD/icon.png -------------------------------------------------------------------------------- /addons/github_to_itch/assets/secrets.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MeagherGames/github_to_itch/HEAD/addons/github_to_itch/assets/secrets.png -------------------------------------------------------------------------------- /addons/github_to_itch/plugin.cfg: -------------------------------------------------------------------------------- 1 | [plugin] 2 | 3 | name="Github To Itch Workflow" 4 | description="Generates a github workflow to export to itch.io automatically when pushing to github" 5 | author="Leonard Meagher" 6 | version="1.0.0" 7 | script="plugin.gd" 8 | -------------------------------------------------------------------------------- /addons/github_to_itch/popup.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=2 format=3 uid="uid://cyjbd25tysr1t"] 2 | 3 | [ext_resource type="PackedScene" uid="uid://c2mxwc6kxe5m2" path="res://addons/github_to_itch/ui/config.tscn" id="1_vmowg"] 4 | 5 | [node name="Control" type="Popup"] 6 | disable_3d = true 7 | title = "Github To Itch Config" 8 | size = Vector2i(578, 816) 9 | visible = true 10 | unresizable = false 11 | borderless = false 12 | min_size = Vector2i(300, 200) 13 | 14 | [node name="Config" parent="." instance=ExtResource("1_vmowg")] 15 | -------------------------------------------------------------------------------- /addons/github_to_itch/assets/secrets.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://du7v2x837whwt" 6 | path="res://.godot/imported/secrets.png-c26bb3c50cf6b47b37a423ad8e328888.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://addons/github_to_itch/assets/secrets.png" 14 | dest_files=["res://.godot/imported/secrets.png-c26bb3c50cf6b47b37a423ad8e328888.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/lossy_quality=0.7 20 | compress/hdr_compression=1 21 | compress/bptc_ldr=0 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Leonard Meagher 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /addons/github_to_itch/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Leonard Meagher 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /addons/github_to_itch/ui/config.gd: -------------------------------------------------------------------------------- 1 | @tool 2 | extends ScrollContainer 3 | 4 | @onready var itch_username = get_node("%Username") 5 | @onready var itch_project_name = get_node("%ProjectName") 6 | 7 | func _ready(): 8 | if ProjectSettings.has_setting("github_to_itch/config/itch_username"): 9 | itch_username.text = ProjectSettings.get_setting("github_to_itch/config/itch_username") 10 | else: 11 | ProjectSettings.set_setting("github_to_itch/config/itch_username", "") 12 | ProjectSettings.add_property_info({ 13 | name = "github_to_itch/config/itch_username", 14 | type = TYPE_STRING 15 | }) 16 | if ProjectSettings.has_setting("github_to_itch/config/itch_project_name"): 17 | itch_project_name.text = ProjectSettings.get_setting("github_to_itch/config/itch_project_name") 18 | else: 19 | ProjectSettings.set_setting("github_to_itch/config/itch_project_name", "") 20 | ProjectSettings.add_property_info({ 21 | name = "github_to_itch/config/itch_project_name", 22 | type = TYPE_STRING 23 | }) 24 | 25 | func _on_meta_clicked(meta): 26 | OS.shell_open(meta) 27 | 28 | func _on_username_text_changed(new_text): 29 | ProjectSettings.set_setting("github_to_itch/config/itch_username", new_text) 30 | ProjectSettings.save() 31 | 32 | func _on_project_name_text_changed(new_text): 33 | ProjectSettings.set_setting("github_to_itch/config/itch_project_name", new_text) 34 | ProjectSettings.save() 35 | -------------------------------------------------------------------------------- /addons/github_to_itch/ui/info_bubble.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=2 format=3 uid="uid://bk128k0tftsey"] 2 | 3 | [sub_resource type="StyleBoxFlat" id="StyleBoxFlat_8hn3d"] 4 | bg_color = Color(0.262745, 0.262745, 0.262745, 1) 5 | corner_radius_top_left = 20 6 | corner_radius_top_right = 20 7 | corner_radius_bottom_right = 20 8 | corner_radius_bottom_left = 20 9 | 10 | [node name="Info" type="HBoxContainer"] 11 | anchor_right = 1.0 12 | anchor_bottom = 1.0 13 | offset_right = -1001.0 14 | offset_bottom = -574.0 15 | rect_min_size = Vector2(26, 26) 16 | size_flags_horizontal = 0 17 | size_flags_vertical = 4 18 | __meta__ = { 19 | "_edit_use_anchors_": false 20 | } 21 | 22 | [node name="Panel" type="Panel" parent="."] 23 | modulate = Color(1, 1, 1, 0.4) 24 | offset_right = 26.0 25 | offset_bottom = 26.0 26 | rect_min_size = Vector2(26, 26) 27 | mouse_filter = 2 28 | size_flags_vertical = 9 29 | theme_override_styles/panel = SubResource( "StyleBoxFlat_8hn3d" ) 30 | __meta__ = { 31 | "_edit_use_anchors_": false 32 | } 33 | 34 | [node name="MarginContainer" type="MarginContainer" parent="Panel"] 35 | anchor_right = 1.0 36 | anchor_bottom = 1.0 37 | mouse_filter = 2 38 | __meta__ = { 39 | "_edit_use_anchors_": false 40 | } 41 | 42 | [node name="Label" type="Label" parent="Panel/MarginContainer"] 43 | offset_right = 26.0 44 | offset_bottom = 26.0 45 | size_flags_vertical = 1 46 | text = "?" 47 | horizontal_alignment = 1 48 | vertical_alignment = 1 49 | -------------------------------------------------------------------------------- /addons/github_to_itch/tempaltes/notify_job.yml: -------------------------------------------------------------------------------- 1 | Notify: 2 | needs: [Export, Release, Publish] 3 | if: ${{ always() }} 4 | env: 5 | DID_PREV_JOBS_SUCCEED: ${{ contains(needs.Export.result, 'success' ) && contains(needs.Release.result, 'success' ) && contains(needs.Publish.result, 'success' ) }} 6 | runs-on: ubuntu-latest 7 | steps: 8 | - uses: actions/download-artifact@v2 9 | if: ${{ env.IS_MAIN && env.DID_PREV_JOBS_SUCCEED == 'true' }} 10 | with: 11 | name: VERSION 12 | 13 | - uses: juliangruber/read-file-action@v1 14 | if: ${{ env.IS_MAIN && env.DID_PREV_JOBS_SUCCEED == 'true' }} 15 | id: version 16 | with: 17 | trim: true 18 | path: ./VERSION.txt 19 | 20 | - name: Send Discord Success Message 21 | if: ${{ env.IS_MAIN && env.DID_PREV_JOBS_SUCCEED == 'true' }} 22 | env: 23 | VERSION: '${{ steps.version.outputs.content }}' 24 | COMMIT_MESSAGE: ${{ github.event.head_commit.message }} 25 | ITCH_URL: 'https://${{env.ITCH_USERNAME}}.itch.io/${{env.ITCH_PROJECT_NAME}}' 26 | run: | 27 | curl --verbose -L $DISCORD_WEBHOOK \ 28 | --header 'Content-Type: application/json' \ 29 | --data "{\"content\": \":white_check_mark: $PROJECT_NAME \`$VERSION\` has **published**!\n**Play**: $ITCH_URL\n**commit**: \`$COMMIT_MESSAGE\`\"}" 30 | 31 | - name: Send Discord Failure Message 32 | if: ${{ env.IS_MAIN && env.DID_PREV_JOBS_SUCCEED != 'true' }} 33 | env: 34 | COMMIT_MESSAGE: ${{ github.event.head_commit.message }} 35 | run: | 36 | curl --verbose -L $DISCORD_WEBHOOK \ 37 | --header 'Content-Type: application/json' \ 38 | --data "{\"content\": \":warning: $PROJECT_NAME workflow has **failed**!\n**Job**: $GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID\n**commit**: $GITHUB_SERVER_URL/$GITHUB_REPOSITORY/commit/$GITHUB_SHA \`$COMMIT_MESSAGE\`\"}" 39 | 40 | 41 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Github To Itch (Godot 4.0) 2 | This addon automatically generates a github workflow to publish your game to your itch.io project. Great for use in jams so you can have your playable code live within a couple minutes of pushing to github. 3 | 4 | # Setup ⚙️ 5 | 1. When enabling the addon a window will popup with instructions on how to setup your `BUTLER_API_KEY` so you can actually push to itch. 6 | 2. You'll also need to configure your Itch Username and Project Name in the popup window so butler will push to the correct account and project. 7 | 3. Create an export preset in `Project > Export` if you don't have one and the addon will add it to your workflow. 8 | 4. :tada: You're ready to go, whenever you push to your `main` branch this workflow will publish to itch.io 9 | To edit the username, or project name go to `Project > Tools > Github to Itch Config` or in your project settings under `github_to_itch/config` 10 | 11 | # How it works 12 | - When an export preset has `runnable=true` this will automatically adjust your github workflow to export and upload that to itch.io with the proper channel. 13 | - The workflow uses [Semantic Versioning](https://www.geeksforgeeks.org/introduction-semantic-versioning/) and [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) based on your commit messages to automatically handle version number updates. 14 | - The workflow also creates a release on your github repo, useful for keeping working copies of your exports. 15 | 16 | ## Customization 17 | The workflow template file is found in `addons/github_to_itch/templates` You can modify that file to change the workflow if needed (maybe you want to change the branch to a `release` branch or something) 18 | 19 | ## Suggestions :+1: 20 | If you have any ideas or suggestions for the addon please create an issue or fork the project and make a PR! 21 | -------------------------------------------------------------------------------- /addons/github_to_itch/plugin.gd: -------------------------------------------------------------------------------- 1 | @tool 2 | extends EditorPlugin 3 | 4 | const Templates = preload("res://addons/github_to_itch/templates.gd") 5 | const ConfigPopup = preload("res://addons/github_to_itch/popup.tscn") 6 | const workflow_path = "res://.github/workflows/github_to_itch.yml" 7 | 8 | var template_helper:Templates = Templates.new() 9 | var timer = Timer.new() 10 | var popup = ConfigPopup.instantiate() 11 | var last_exports_modified_time:int 12 | var last_project_modified_time:int 13 | 14 | func save(forced = false): 15 | 16 | var export_modified_time = FileAccess.get_modified_time("res://export_presets.cfg") 17 | var project_modified_time = FileAccess.get_modified_time("res://project.godot") 18 | 19 | if forced or export_modified_time != last_exports_modified_time or project_modified_time != last_project_modified_time: 20 | last_exports_modified_time = export_modified_time 21 | last_project_modified_time = project_modified_time 22 | 23 | var workflow_directory = workflow_path.get_base_dir() 24 | if not DirAccess.dir_exists_absolute(workflow_directory): 25 | DirAccess.make_dir_recursive_absolute(workflow_directory) 26 | 27 | var file = FileAccess.open(workflow_path, FileAccess.WRITE) 28 | file.store_string(template_helper.workflow()) 29 | 30 | func _enter_tree(): 31 | 32 | timer.one_shot = true 33 | timer.wait_time = 1.0 34 | timer.connect("timeout", _timer_timeout) 35 | 36 | add_child(timer) 37 | 38 | _timer_timeout() 39 | connect("project_settings_changed", func(): save(true)) 40 | add_tool_menu_item("Github To Itch Config", show_popup) 41 | 42 | if not ProjectSettings.has_setting("github_to_itch/config/itch_username") || not ProjectSettings.has_setting("github_to_itch/config/itch_project_name"): 43 | show_popup() 44 | 45 | 46 | func _exit_tree(): 47 | remove_child(timer) 48 | if popup.get_parent(): 49 | popup.get_parent().remove_child(popup) 50 | remove_tool_menu_item("Github To Itch Config") 51 | 52 | func _timer_timeout(): 53 | save() 54 | timer.start() 55 | 56 | func show_popup(): 57 | if not popup.get_parent(): 58 | add_child(popup) 59 | popup.popup_centered(Vector2i(1000,600)) 60 | -------------------------------------------------------------------------------- /addons/github_to_itch/tempaltes/workflow_template.yml: -------------------------------------------------------------------------------- 1 | name: Publish {PROJECT_NAME} to Itch.io 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | branches: 9 | - main 10 | env: 11 | BUTLER_API_KEY: ${{ secrets.BUTLER_API_KEY }} # Needs to be added through github 12 | DISCORD_WEBHOOK: ${{secrets.DISCORD_WEBHOOK}} # Needs to be added through github 13 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 14 | IS_MAIN: ${{ contains(github.ref, 'main') }} 15 | PROJECT_NAME: "{PROJECT_NAME}" 16 | 17 | jobs: 18 | CleanArtifacts: 19 | # This job clears out the previous artifacts made so you don't run out of space in your github account 20 | runs-on: ubuntu-latest 21 | steps: 22 | - uses: kolpav/purge-artifacts-action@v1 23 | with: 24 | token: ${{ secrets.GITHUB_TOKEN }} 25 | expire-in: 1hr 26 | 27 | Export: 28 | needs: CleanArtifacts # wait for artifacts to clean before making a new one 29 | runs-on: ubuntu-latest 30 | steps: 31 | - uses: actions/checkout@v2 32 | 33 | - name: Download + Authorize Godot 34 | run: | 35 | curl -L -o godot.zip https://downloads.tuxfamily.org/godotengine/{GODOT_PATH}/Godot_v{GODOT_VERSION}-{GODOT_STATUS}_linux.x86_64.zip 36 | unzip godot.zip 37 | mv Godot_v{GODOT_VERSION}-{GODOT_STATUS}_linux.x86_64 godot 38 | ls 39 | chmod +x godot 40 | 41 | - name: Download Export Templates 42 | run: | 43 | curl -L -o export_templates.zip https://downloads.tuxfamily.org/godotengine/{GODOT_PATH}/Godot_v{GODOT_VERSION}-{GODOT_STATUS}_export_templates.tpz 44 | unzip export_templates.zip 45 | 46 | - name: Install Export Templates 47 | run: | 48 | mkdir -p ~/.local/share/godot/export_templates/{GODOT_VERSION}.{GODOT_STATUS} 49 | mv ./templates/* ~/.local/share/godot/export_templates/{GODOT_VERSION}.{GODOT_STATUS} 50 | 51 | {EXPORTS_FROM_GODOT} 52 | - uses: actions/upload-artifact@v2 53 | with: 54 | name: exports 55 | path: exports 56 | 57 | Release: 58 | needs: Export 59 | if: ${{ contains(github.ref, 'main') }} 60 | runs-on: ubuntu-latest 61 | steps: 62 | - uses: actions/checkout@v2 63 | 64 | - name: Version 65 | id: tag_version 66 | uses: mathieudutour/github-tag-action@v5.6 67 | with: 68 | github_token: ${{ secrets.GITHUB_TOKEN }} 69 | 70 | - name: Verify Tag 71 | if: ${{ !steps.tag_version.outputs.new_tag }} 72 | run: exit 1 73 | 74 | - name: Download Exports 75 | uses: actions/download-artifact@v2 76 | with: 77 | name: exports 78 | path: exports 79 | 80 | - name: Zip 81 | run: zip -r release-${{ steps.tag_version.outputs.new_tag }}.zip exports 82 | 83 | - name: Create Github Release 84 | id: create_release 85 | uses: actions/create-release@v1 86 | env: 87 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 88 | with: 89 | tag_name: ${{ steps.tag_version.outputs.new_tag }} 90 | release_name: Release ${{ steps.tag_version.outputs.new_tag }} 91 | body: ${{ steps.tag_version.outputs.changelog }} 92 | 93 | - name: Upload Release Artifact 94 | uses: actions/upload-release-asset@v1 95 | env: 96 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 97 | with: 98 | upload_url: ${{ steps.create_release.outputs.upload_url }} 99 | asset_path: ./release-${{ steps.tag_version.outputs.new_tag }}.zip 100 | asset_name: release-${{ steps.tag_version.outputs.new_tag }}.zip 101 | asset_content_type: application/zip 102 | 103 | - uses: frdrwrt/write-to-file@v1.3 104 | with: 105 | filepath: ./VERSION.txt 106 | content: ${{ steps.tag_version.outputs.new_version }} 107 | mode: 0655 108 | 109 | - uses: actions/upload-artifact@v2 110 | with: 111 | name: VERSION 112 | path: ./VERSION.txt 113 | 114 | Publish: 115 | needs: Release 116 | if: ${{ contains(github.ref, 'main') }} 117 | runs-on: ubuntu-latest 118 | steps: 119 | - uses: actions/download-artifact@v2 120 | 121 | - name: Download + Authorize Butler 122 | run: | 123 | curl -L -o butler.zip https://broth.itch.ovh/butler/linux-amd64/LATEST/archive/default 124 | unzip butler.zip 125 | chmod +x butler 126 | ./butler -V 127 | 128 | - name: Login To Butler 129 | run: ./butler login 130 | 131 | {UPLOADS_TO_ITCH} 132 | Cleanup: 133 | needs: [Export, Release, Publish] 134 | runs-on: ubuntu-latest 135 | steps: 136 | - uses: geekyeggo/delete-artifact@v1 137 | with: 138 | name: VERSION 139 | -------------------------------------------------------------------------------- /addons/github_to_itch/templates.gd: -------------------------------------------------------------------------------- 1 | @tool 2 | extends RefCounted 3 | 4 | ## Helper script to render the workflow yml file 5 | 6 | const workflow_template_path:String = "res://addons/github_to_itch/tempaltes/workflow_template.yml" 7 | const export_template_path:String = "res://addons/github_to_itch/tempaltes/export.yml" 8 | 9 | const ITCH_CHANNEL_MAP = { 10 | "HTML5": "web", 11 | "Windows Desktop": "win", 12 | "Android": "android", 13 | "iOS": "ios", # not an official channel of itch 14 | "Linux/X11": "linux", 15 | "macOS": "mac", 16 | "UWP": "uwp" # not an official channel of itch 17 | } 18 | 19 | var export_template:String = """ - name: Export {PLATFORM} 20 | run: | 21 | mkdir -p ./{EXPORT_PATH} 22 | ./godot --headless --path ./ --export-release "{NAME}" ./{EXPORT_FILE} 23 | 24 | """.replace("\t", " ") 25 | var uploads_template:String = """ - name: Push {PLATFORM} to Itch 26 | run: ./butler push {EXPORT_PATH} {ITCH_USERNAME}/{ITCH_PROJECT_NAME}:{ITCH_CHANNEL} --userversion-file ./VERSION/VERSION.txt 27 | 28 | """.replace("\t", " ") 29 | 30 | static func get_version_info() -> Dictionary: 31 | var info = Engine.get_version_info() 32 | var version = str(info.major) + "." + str(info.minor) 33 | if info.patch != 0: 34 | version += "." + str(info.patch) 35 | 36 | return { 37 | version = version, 38 | status = info.status 39 | } 40 | 41 | static func get_project_name() -> String: 42 | return ProjectSettings.get("application/config/name") 43 | 44 | static func get_exports() -> Array[Dictionary]: 45 | var res:Array[Dictionary] = [] 46 | var config := ConfigFile.new() 47 | config.load("res://export_presets.cfg") 48 | var needs_saving = false 49 | 50 | for section in config.get_sections(): 51 | if config.has_section_key(section, "exclude_filter"): 52 | # Set addon to be excluded 53 | var exclude_filter:String = config.get_value(section, "exclude_filter", "") 54 | var parts = exclude_filter.split(",", false) 55 | if not "addons/github_to_itch/*" in parts: 56 | parts.append("addons/github_to_itch/*") 57 | exclude_filter = ",".join(parts) 58 | config.set_value(section, "exclude_filter", exclude_filter) 59 | needs_saving = true 60 | 61 | 62 | if config.get_value(section, "runnable", false): 63 | res.append({ 64 | name = config.get_value(section, "name"), 65 | platform = config.get_value(section, "platform"), 66 | export_path = config.get_value(section, "export_path"), 67 | }) 68 | 69 | if needs_saving: 70 | config.save("res://export_presets.cfg") 71 | 72 | return res 73 | 74 | func exports() -> String: 75 | 76 | var exports = get_exports() 77 | 78 | var res:PackedStringArray 79 | for export in exports: 80 | res.append(export_template.format({ 81 | NAME = export.name, 82 | PLATFORM = export.platform, 83 | EXPORT_PATH = export.export_path.get_base_dir(), 84 | EXPORT_FILE = export.export_path 85 | })) 86 | 87 | return "".join(res) 88 | 89 | func uploads() -> String: 90 | var exports = get_exports() 91 | var ITCH_USERNAME = ProjectSettings.get_setting("github_to_itch/config/itch_username") 92 | var ITCH_PROJECT_NAME = ProjectSettings.get_setting("github_to_itch/config/itch_project_name") 93 | 94 | var res:PackedStringArray 95 | for export in exports: 96 | res.append(uploads_template.format({ 97 | PLATFORM = export.platform, 98 | EXPORT_PATH = "./" + export.export_path.get_base_dir(), 99 | ITCH_CHANNEL = ITCH_CHANNEL_MAP[export.platform], 100 | ITCH_USERNAME = ITCH_USERNAME.to_lower(), 101 | ITCH_PROJECT_NAME = ITCH_PROJECT_NAME.to_lower() 102 | })) 103 | 104 | return "".join(res) 105 | 106 | func workflow() -> String: 107 | var file := FileAccess.open(workflow_template_path, FileAccess.READ) 108 | var workflow_template = file.get_as_text() 109 | 110 | var version_info = get_version_info() 111 | var GODOT_PATH = version_info.version 112 | 113 | if version_info.status != "stable": 114 | GODOT_PATH += "/" + version_info.status 115 | 116 | return workflow_template.replace("\t", " ").format({ 117 | PROJECT_NAME = get_project_name(), 118 | GODOT_VERSION = version_info.version, 119 | GODOT_STATUS = version_info.status, 120 | GODOT_PATH = GODOT_PATH, 121 | ITCH_PROJECT_NAME = ProjectSettings.get_setting("github_to_itch/config/itch_project_name"), 122 | ITCH_USERNAME = ProjectSettings.get_setting("github_to_itch/config/itch_username"), 123 | EXPORTS_FROM_GODOT = exports(), 124 | UPLOADS_TO_ITCH = uploads() 125 | }) 126 | -------------------------------------------------------------------------------- /addons/github_to_itch/ui/config.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=3 format=3 uid="uid://c2mxwc6kxe5m2"] 2 | 3 | [ext_resource type="Script" path="res://addons/github_to_itch/ui/config.gd" id="1_06q30"] 4 | [ext_resource type="PackedScene" uid="uid://bk128k0tftsey" path="res://addons/github_to_itch/ui/info_bubble.tscn" id="2_kphco"] 5 | 6 | [node name="ScrollContainer" type="ScrollContainer"] 7 | anchors_preset = 15 8 | anchor_right = 1.0 9 | anchor_bottom = 1.0 10 | grow_horizontal = 2 11 | grow_vertical = 2 12 | horizontal_scroll_mode = 0 13 | script = ExtResource("1_06q30") 14 | 15 | [node name="Config" type="MarginContainer" parent="."] 16 | layout_mode = 2 17 | size_flags_horizontal = 3 18 | size_flags_vertical = 3 19 | theme_override_constants/margin_left = 8 20 | theme_override_constants/margin_top = 8 21 | theme_override_constants/margin_right = 8 22 | theme_override_constants/margin_bottom = 8 23 | 24 | [node name="Control" type="VBoxContainer" parent="Config"] 25 | layout_mode = 2 26 | size_flags_horizontal = 3 27 | size_flags_vertical = 3 28 | 29 | [node name="ItchInfo" type="PanelContainer" parent="Config/Control"] 30 | layout_mode = 2 31 | 32 | [node name="MarginContainer" type="MarginContainer" parent="Config/Control/ItchInfo"] 33 | layout_mode = 2 34 | theme_override_constants/margin_left = 8 35 | theme_override_constants/margin_top = 8 36 | theme_override_constants/margin_right = 8 37 | theme_override_constants/margin_bottom = 8 38 | 39 | [node name="GridContainer" type="GridContainer" parent="Config/Control/ItchInfo/MarginContainer"] 40 | layout_mode = 2 41 | size_flags_horizontal = 3 42 | columns = 3 43 | 44 | [node name="Label" type="Label" parent="Config/Control/ItchInfo/MarginContainer/GridContainer"] 45 | layout_mode = 2 46 | text = "Itch Username:" 47 | vertical_alignment = 2 48 | 49 | [node name="Username" type="LineEdit" parent="Config/Control/ItchInfo/MarginContainer/GridContainer"] 50 | unique_name_in_owner = true 51 | layout_mode = 2 52 | placeholder_text = "username" 53 | expand_to_text_length = true 54 | 55 | [node name="Info" parent="Config/Control/ItchInfo/MarginContainer/GridContainer" instance=ExtResource("2_kphco")] 56 | layout_mode = 2 57 | 58 | [node name="Example" type="Label" parent="Config/Control/ItchInfo/MarginContainer/GridContainer/Info"] 59 | modulate = Color(1, 1, 1, 0.4) 60 | layout_mode = 2 61 | text = "What you log in with" 62 | 63 | [node name="Label2" type="Label" parent="Config/Control/ItchInfo/MarginContainer/GridContainer"] 64 | layout_mode = 2 65 | text = "Itch Project Name:" 66 | vertical_alignment = 2 67 | 68 | [node name="ProjectName" type="LineEdit" parent="Config/Control/ItchInfo/MarginContainer/GridContainer"] 69 | unique_name_in_owner = true 70 | layout_mode = 2 71 | placeholder_text = "project-name" 72 | expand_to_text_length = true 73 | 74 | [node name="Info2" parent="Config/Control/ItchInfo/MarginContainer/GridContainer" instance=ExtResource("2_kphco")] 75 | layout_mode = 2 76 | 77 | [node name="Label4" type="Label" parent="Config/Control/ItchInfo/MarginContainer/GridContainer/Info2"] 78 | modulate = Color(1, 1, 1, 0.4) 79 | layout_mode = 2 80 | text = "Found in itch url" 81 | 82 | [node name="PanelContainer" type="PanelContainer" parent="Config/Control"] 83 | layout_mode = 2 84 | 85 | [node name="MarginContainer" type="MarginContainer" parent="Config/Control/PanelContainer"] 86 | layout_mode = 2 87 | theme_override_constants/margin_left = 8 88 | theme_override_constants/margin_top = 8 89 | theme_override_constants/margin_right = 8 90 | theme_override_constants/margin_bottom = 8 91 | 92 | [node name="VBoxContainer" type="VBoxContainer" parent="Config/Control/PanelContainer/MarginContainer"] 93 | layout_mode = 2 94 | 95 | [node name="Instructions" type="RichTextLabel" parent="Config/Control/PanelContainer/MarginContainer/VBoxContainer"] 96 | layout_mode = 2 97 | size_flags_vertical = 3 98 | focus_mode = 2 99 | theme_override_constants/outline_size = 0 100 | bbcode_enabled = true 101 | text = "[b]If you haven't setup your project in Itch, [color=#8af][url=https://itch.io/dashboard]do that first[/url][/color][/b]. 102 | 103 | [font_size=24][center]Secrets in Github[/center][/font_size] 104 | [ol] Go to [color=#8af][url]https://itch.io/user/settings/api-keys[/url][/color] and generate a new api key or use an existing one. 105 | Copy that code and go to your github repo settings 106 | On the lefthand side find Secrets > Actions and add the API key as a secret with the name [code][bgcolor=#444] BUTLER_API_KEY [/bgcolor][/code][/ol] 107 | 108 | [center][img=center,center]res://addons/github_to_itch/assets/secrets.png[/img][/center]" 109 | fit_content_height = true 110 | scroll_active = false 111 | selection_enabled = true 112 | deselect_on_focus_loss_enabled = false 113 | 114 | [connection signal="text_changed" from="Config/Control/ItchInfo/MarginContainer/GridContainer/Username" to="." method="_on_username_text_changed"] 115 | [connection signal="text_changed" from="Config/Control/ItchInfo/MarginContainer/GridContainer/ProjectName" to="." method="_on_project_name_text_changed"] 116 | [connection signal="meta_clicked" from="Config/Control/PanelContainer/MarginContainer/VBoxContainer/Instructions" to="." method="_on_meta_clicked"] 117 | --------------------------------------------------------------------------------