├── test_locales ├── pt.yml └── en.yml ├── docker-test.env ├── .dockerignore ├── bin └── tag-name.sh ├── .tx └── config ├── Dockerfile ├── git-flow-docker-test.env ├── CHANGELOG.md ├── another_test_locales └── en.yml ├── LICENSE ├── action.yml ├── entrypoint.sh └── README.md /test_locales/pt.yml: -------------------------------------------------------------------------------- 1 | pt: 2 | alice_in_wonderland: 3 | quote_one: "" 4 | quote_two: "" 5 | quote_three: "" 6 | quote_four: "" 7 | -------------------------------------------------------------------------------- /docker-test.env: -------------------------------------------------------------------------------- 1 | INPUT_PUSH_SOURCES=true 2 | INPUT_PUSH_TRANSLATIONS=true 3 | INPUT_PULL_SOURCES=true 4 | INPUT_PULL_TRANSLATIONS=true 5 | INPUT_MINIMUM_PERC=50 6 | INPUT_DISABLE_OVERRIDE=true 7 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | /.git/ 2 | /.github/ 3 | /bin/ 4 | /.editorconfig 5 | /.gitattributes 6 | /.gitignore 7 | /.tx/ 8 | /test_locales/ 9 | /CHANGELOG.md 10 | /LICENSE 11 | /Makefile 12 | /README.md 13 | -------------------------------------------------------------------------------- /bin/tag-name.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | GITHUB_REF=$1 4 | 5 | if [[ -n $GITHUB_REF && $GITHUB_REF == refs/tags/* ]]; then 6 | echo "${GITHUB_REF#refs/tags/}"; 7 | 8 | exit 0 9 | fi 10 | 11 | echo "Unable to determine tag name from '${GITHUB_REF}'" 12 | 13 | exit 1; 14 | -------------------------------------------------------------------------------- /.tx/config: -------------------------------------------------------------------------------- 1 | [main] 2 | host = https://www.transifex.com 3 | 4 | [github-actions-test.test_locales] 5 | file_filter = test_locales/.yml 6 | source_file = test_locales/en.yml 7 | source_lang = en 8 | type = YML 9 | 10 | 11 | [github-actions-test.another_test_locales] 12 | file_filter = another_test_locales/.yml 13 | source_file = another_test_locales/en.yml 14 | source_lang = en 15 | type = YML 16 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.7 2 | 3 | LABEL "repository"="https://github.com/sergioisidoro/github-transifex-action" 4 | LABEL "homepage"="https://github.com/sergioisidoro/github-transifex-action" 5 | LABEL "maintainer"="Sergio Isidoro " 6 | 7 | 8 | RUN pip install transifex-client 9 | RUN apt-get install git 10 | 11 | ADD entrypoint.sh /entrypoint.sh 12 | 13 | ENTRYPOINT ["/entrypoint.sh"] 14 | -------------------------------------------------------------------------------- /git-flow-docker-test.env: -------------------------------------------------------------------------------- 1 | INPUT_PUSH_SOURCES=true 2 | INPUT_PUSH_TRANSLATIONS=true 3 | INPUT_PULL_SOURCES=true 4 | INPUT_PULL_TRANSLATIONS=true 5 | INPUT_MINIMUM_PERC=50 6 | INPUT_DISABLE_OVERRIDE=true 7 | INPUT_GITHUB_TOKEN=secretz 8 | INPUT_GIT_FLOW=true 9 | INPUT_TRANSLATIONS_FOLDER=test_locales another_test_locales 10 | INPUT_COMMITTER_EMAIL=test@tx-actions.com 11 | INPUT_COMMITTER_NAME=tx-action 12 | INPUT_GIT_UNSHALLOW=false 13 | INPUT_COMMIT_TO_PR=true 14 | -------------------------------------------------------------------------------- /test_locales/en.yml: -------------------------------------------------------------------------------- 1 | en: 2 | alice_in_wonderland: 3 | quote_one: Why, sometimes I've believed as many as six impossible things before breakfast 4 | quote_two: It's no use going back to yesterday, because I was a different person then. 5 | quote_three: It takes all the running you can do, to keep in the same place. If you want to get somewhere else, you must run at least twice as fast as that! 6 | quote_four: Who in the world am I?' Ah, that's the great puzzle! 7 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## v0.2.0 4 | * [Git workflow](https://github.com/sergioisidoro/github-transifex-action/blob/81fef75/README.md#git-workflow) 5 | 6 | ### BREAKING CHANGES 7 | * Replaces `env` parameter in action configuration with the keyword `with` 8 | 9 | ### DEPRECATION WARNINGS 10 | * In future git workflow will be the default mode for the action! 11 | * This will be made together with timestamp comparison with git commit timestamps - https://github.com/transifex/transifex-client/pull/290 12 | 13 | 14 | ## Unreleased 15 | -------------------------------------------------------------------------------- /another_test_locales/en.yml: -------------------------------------------------------------------------------- 1 | en: 2 | allan_watts: 3 | quote_one: Life is like music for its own sake. We are living in an eternal now, and when we listen to music we are not listening to the past, we are not listening to the future, we are listening to an expanded present. 4 | quote_two: No valid plans for the future can be made by those who have no capacity for living now. 5 | quote_three: I have realized that the past and future are real illusions, that they exist in the present, which is what there is and all there is. 6 | quote_four: Trying to define yourself is like trying to bite your own teeth. 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2020 Sergio Isidoro 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 6 | documentation files (the "Software"), to deal in the Software without restriction, including without limitation the 7 | rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit 8 | persons to whom the Software is furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the 11 | Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 14 | WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 16 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | # https://help.github.com/en/articles/metadata-syntax-for-github-actions 2 | 3 | author: 'sergioisidoro' 4 | 5 | branding: 6 | icon: 'box' 7 | color: 'green' 8 | 9 | description: 'Push your strings automatically to Transifex when PR is ready for translations' 10 | 11 | name: 'github-transifex-actions' 12 | 13 | runs: 14 | using: 'docker' 15 | image: 'docker://sergioisidoro/github-transifex-action' 16 | 17 | inputs: 18 | tx_token: 19 | description: 'Transifex Token' 20 | required: true 21 | push_sources: 22 | description: 'Pushes source locales to Transifex' 23 | required: false 24 | default: 'true' 25 | push_translations: 26 | description: 'Pushes Translations to Transifex' 27 | default: 'false' 28 | required: false 29 | pull_sources: 30 | description: 'Pulls sources from Transifex' 31 | required: false 32 | default: 'true' 33 | pull_translations: 34 | description: 'Pulls Translations from Transifex' 35 | default: 'true' 36 | required: false 37 | commit_to_pr: 38 | description: 'Commits the results of the merge / pulls to the PR' 39 | default: 'false' 40 | required: false 41 | minimum_perc: 42 | description: 'Minimum percentage the files need to be translated to be fetched' 43 | default: '0' 44 | required: false 45 | disable_override: 46 | description: 'If true it will not override the files locally (WARN: Has issues with git)' 47 | default: 'false' 48 | required: false 49 | git_flow: 50 | description: 'Should use Git flow?' 51 | default: 'true' 52 | required: false 53 | git_unshallow: 54 | description: 'Unshallow git (required in git workflow if the git clone action only does shallow clone)' 55 | default: 'true' 56 | required: false 57 | current_branch: 58 | description: 'The current branch that is under work. Defaults to GITHUB_HEAD_REF' 59 | required: false 60 | master_branch: 61 | description: 'The branch that is used as master. Defaults to master' 62 | default: 'master' 63 | required: false 64 | github_token: 65 | description: 'Github required for git flow' 66 | required: false 67 | translations_folder: 68 | description: 'The wildcard-able expression for the folder containing the locales. Eg /config/locales' 69 | required: false 70 | committer_email: 71 | description: 'The email of the author of commit' 72 | default: 'git-action@transifex.com' 73 | required: false 74 | committer_name: 75 | default: 'Transifex Github action' 76 | description: 'The email of the author of commit' 77 | required: false 78 | skip_push_commit: 79 | description: 'Does not push anything back to git remote (used for testing)' 80 | required: false 81 | default: 'false' 82 | parallel: 83 | description: 'Pushes or pulls things from transifex in parallel' 84 | required: false 85 | default: 'false' 86 | -------------------------------------------------------------------------------- /entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # exit when any command fails 4 | set -e 5 | if [[ $INPUT_DEBUG ]] ; then 6 | set -x 7 | fi 8 | echo "STARTING TRANSIFEX ACTION..." 9 | 10 | CURRENT_BRANCH=${INPUT_CURRENT_BRANCH:-$GITHUB_HEAD_REF} 11 | MASTER_BRANCH=${INPUT_MASTER_BRANCH:-master} 12 | REMOTE=${INPUT_REMOTE:-origin} 13 | TRANSLATIONS_FOLDER=${INPUT_TRANSLATIONS_FOLDER} 14 | SKIP_PUSH_COMMIT=${INPUT_SKIP_PUSH_COMMIT} 15 | 16 | COMMITER_EMAIL=${INPUT_COMMITER_EMAIL:-'git-action@transifex.com'} 17 | COMMITTER_NAME=${INPUT_COMMITTER_NAME:-'Transifex Github action'} 18 | 19 | export TX_TOKEN=${INPUT_TX_TOKEN:-$TX_TOKEN} 20 | 21 | # Because transifex overrides whatever is in remote with what's currently in 22 | # our branch, we will do the following: 23 | # 1 - Checkout master (or whatever base branch) 24 | # 2 - Get what's in transifex 25 | # 3 - Use commit to the staging area 26 | # 4 - Use git merge with fast-forward only so we merge the differences 27 | # 5 - Push the merge result to transifex 28 | 29 | args=() 30 | common_args=() 31 | 32 | if [[ "$INPUT_PARALLEL" = true ]] ; then 33 | common_args+=( "--parallel" ) 34 | fi 35 | 36 | if [[ $INPUT_MINIMUM_PERC -ne 0 ]] ; then 37 | args+=( "--minimum-perc=$INPUT_MINIMUM_PERC" ) 38 | fi 39 | 40 | if [[ "$INPUT_DISABLE_OVERRIDE" = true ]] ; then 41 | args+=( "--disable-overwrite" ) 42 | fi 43 | 44 | if [[ "$INPUT_PULL_SOURCES" = true ]] ; then 45 | args+=( "-s" ) 46 | fi 47 | 48 | if [[ "$INPUT_PULL_TRANSLATIONS" = true ]] ; then 49 | args+=( "-a" ) 50 | fi 51 | 52 | if [[ "$INPUT_GIT_FLOW" = true ]] ; then 53 | echo "USING GIT MERGE FLOW" 54 | 55 | [[ -z "${INPUT_GITHUB_TOKEN}" ]] && { 56 | echo 'Missing input "github_token: ${{ secrets.GITHUB_TOKEN }}".'; 57 | exit 1; 58 | }; 59 | 60 | echo "Setting up git repo" 61 | git config --global user.email "${COMMITTER_EMAIL}" 62 | git config --global user.name "${COMMITTER_NAME}" 63 | remote_repo="https://${GITHUB_ACTOR}:${INPUT_GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" 64 | 65 | 66 | if [[ "$INPUT_GIT_UNSHALLOW" != false ]] ; then 67 | # Git checkout action does a shallow clone. That prevents us to 68 | # access common history of branches. 69 | git fetch --unshallow 70 | fi 71 | 72 | git checkout origin/${MASTER_BRANCH} 73 | TRANSLATIONS_MERGE_BRANCH="${MASTER_BRANCH}-translations-$(date +%s)" 74 | git checkout -b ${TRANSLATIONS_MERGE_BRANCH} 75 | 76 | if [[ "$INPUT_PULL_SOURCES" = true ]] || [[ "$INPUT_PULL_TRANSLATIONS" = true ]] ; then 77 | echo "Pulling most up to date sources and translations" 78 | # Unfortunately we need to use force because transifex thinks the checked out 79 | # files are newer than in Transifex, so they get ignored. See issue: 80 | # https://github.com/transifex/transifex-client/issues/22 81 | tx pull --no-interactive --force "${common_args[@]}" "${args[@]}" 82 | else 83 | echo "WARNING - NOT PULLING ANY STRINGS FROM TRANSIFEX - PUSHING WILL RESULT IN OVERRIDING THE STRINGS IN TRANSIFEX" 84 | fi 85 | 86 | # Commits latest transifex tranlsations to our local branch 87 | git add $(echo ${TRANSLATIONS_FOLDER}) 88 | 89 | git diff --staged 90 | 91 | # Stashes all of the non needed changes (eg. sometines .tx/config is changed) 92 | git diff --staged --quiet || git commit -m "Update translations" && git stash && git merge --no-edit origin/$CURRENT_BRANCH 93 | 94 | # and let's push the merged version upstream 95 | 96 | if [[ "$INPUT_PUSH_SOURCES" = true ]] ; then 97 | tx push -s --no-interactive "${common_args[@]}" 98 | fi 99 | 100 | if [[ "$INPUT_PUSH_TRANSLATIONS" = true ]] ; then 101 | tx push -t --no-interactive "${common_args[@]}" 102 | fi 103 | 104 | if [[ "$INPUT_COMMIT_TO_PR" = true ]] ; then 105 | # Stashes all of the non needed changes (eg. sometines .tx/config is changed) 106 | git stash 107 | git checkout $CURRENT_BRANCH 108 | git checkout ${TRANSLATIONS_MERGE_BRANCH} -- $TRANSLATIONS_FOLDER 109 | git add $(echo ${TRANSLATIONS_FOLDER}) 110 | git diff --staged --quiet || git commit -m "Update translations from Transifex" 111 | 112 | if [[ "$SKIP_PUSH_COMMIT" = true ]] ; then 113 | echo "SKIPPING PUSH!" 114 | else 115 | git push "${remote_repo}" HEAD:${CURRENT_BRANCH} 116 | fi 117 | fi 118 | else 119 | echo "USING OVERRIDE FLOW" 120 | if [[ "$INPUT_PULL_SOURCES" = true ]] ; then 121 | echo "PULLING SOURCES" 122 | tx pull -s --force --no-interactive "${common_args[@]}" 123 | fi 124 | 125 | if [[ "$INPUT_PULL_TRANSLATIONS" = true ]] ; then 126 | echo "PULLING TRANSLATIONS (with args: $args)" 127 | tx pull -a --force --no-interactive "${args[@]}" "${common_args[@]}" 128 | fi 129 | 130 | if [[ "$INPUT_PUSH_SOURCES" = true ]] ; then 131 | echo "PUSHING SOURCES" 132 | tx push -s --no-interactive "${common_args[@]}" 133 | fi 134 | 135 | if [[ "$INPUT_PUSH_TRANSLATIONS" = true ]] ; then 136 | echo "PUSHING TRANSLATIONS" 137 | tx push -t --no-interactive "${common_args[@]}" 138 | fi 139 | fi 140 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Github Transifex Action 🌎💬⚙️ 2 | 3 | **⚠️ New versions might have breaking changes.** 4 | 5 | Please pin your git action version ([List here](https://github.com/sergioisidoro/github-transifex-action/tags)) instead of using `latest`, so that breaking changes do not break your workflow ([see bellow](https://github.com/sergioisidoro/github-transifex-action#docker-image)) You can also use the version `edge` for the current unreleased version (master branch) of this action 6 | 7 | ## What does this action do? 8 | 9 | - For now it just pushes the source strings to Transifex, as long as you configure the `TX_TOKEN` to the enviroment of the job. 10 | 11 | ## Usage 12 | 13 | Define a workflow in `.github/workflows/transifex.yml` (or add a job if you already have defined workflows). 14 | 15 | :bulb: Read more about [Configuring a workflow](https://help.github.com/en/articles/configuring-a-workflow). 16 | 17 | ```yaml 18 | on: 19 | pull_request: 20 | types: [labeled] 21 | 22 | name: "Translations Sync" 23 | 24 | jobs: 25 | push-strings-to-transifex: 26 | if: github.event.label.name == 'Ready for translations' 27 | name: push-strings-to-transifex 28 | 29 | runs-on: ubuntu-latest 30 | 31 | steps: 32 | - name: "Checkout" 33 | uses: actions/checkout@master 34 | 35 | - name: "Run action" 36 | with: 37 | TX_TOKEN: ${{ secrets.TX_TOKEN }} 38 | uses: docker://sergioisidoro/github-transifex-action:v0.2.0 39 | ``` 40 | 41 | 42 | ## What commands are supported? 43 | Because you might have multiple branches ongoing, and you might not want to override what the other branch have 44 | pushed to transifex, this action offers a solution for handling the diff of transifex remote and the current branch with git. 45 | 46 | 1. It will pull things from transifex remote into a separate branch, 47 | 2. merge your current branch into the branch with the transifex content (and resolving the diff) 48 | 4. Push things back to transifex 49 | 5. Commit the state into your PR 50 | 51 | That way you have what's in transifex + all the changes you've made in the current branch. 52 | Of course if there are merge conflicts you will need to take manual action. 53 | 54 | ## Important note 55 | 56 | ⚠️ If you have `pull_sources: false` or `pull_translations: false` this action will not pull things from transifex. This means that if you use any of the push commands, that action will override transifex content without using the merging functionality of this action. These inputs have default true to prevent accidental overrides. 57 | 58 | ## Use cases 59 | Here are the most common use cases for this action 60 | 61 | NOTE: `github_token` and `translations_folder` are required if you use `git_flow` 62 | ### Push to transifex without messing with strings pushed from other PRs: 63 | ``` 64 | - name: "Merge and push to transifex" 65 | with: # Or as an environment variable 66 | tx_token: ${{ secrets.TX_TOKEN }} 67 | git_flow: true 68 | github_token: ${{ secrets.GITHUB_TOKEN }} 69 | translations_folder: config/locale 70 | pull_translations: true 71 | pull_sources: true 72 | push_translations: true 73 | push_sources: true 74 | ``` 75 | ### Pull the entire current state from Transifex and commit to the PR: 76 | ``` 77 | - name: "Pull from transifex and commit to the PR" 78 | with: # Or as an environment variable 79 | tx_token: ${{ secrets.TX_TOKEN }} 80 | git_flow: true 81 | github_token: ${{ secrets.GITHUB_TOKEN }} 82 | translations_folder: config/locale 83 | pull_translations: true 84 | pull_sources: true 85 | commit_to_pr: true 86 | ``` 87 | ### Reset Transifex with what you currently have in your branch (DANGER) 88 | ``` 89 | - name: "Reset Transifex with current state" 90 | with: # Or as an environment variable 91 | tx_token: ${{ secrets.TX_TOKEN }} 92 | git_flow: true 93 | github_token: ${{ secrets.GITHUB_TOKEN }} 94 | translations_folder: config/locale 95 | pull_translations: false 96 | pull_sources: false 97 | push_translations: true 98 | push_sources: true 99 | ``` 100 | 101 | ### Simple workflow ( DEPRECATED ! ) 102 | DEPRECATED - This action does not require a git token, or a translation folder input. But it can only push sources and translations without merging the transifex state. It does not support commit to the PR, and push command will override anything in Transifex with the current state of the pull request. 103 | 104 | Support for simple workflow will be removed on the next releases. 105 | ``` 106 | - name: "Run action" 107 | with: # Or as an environment variable 108 | git_flow: false 109 | tx_token: ${{ secrets.TX_TOKEN }} 110 | push_sources: true 111 | push_translations: true 112 | disable_override: false 113 | ``` 114 | 115 | ### Supported inputs and options. 116 | See [the action input description](https://github.com/sergioisidoro/github-transifex-action/blob/master/action.yml#L17) for a full understanding of what the action supports 117 | ### Docker image 118 | 119 | As Docker images are automatically built and pushed on a merge to `master` or when a new tag is created in this repository, the recommended way to use this GitHub action is to reference the pre-built Docker image directly, as seen above. 120 | 121 | :bulb: The Docker image can also be executed directly by running 122 | 123 | ``` 124 | $ docker run --interactive --rm --tty --workdir=/app --volume ${PWD}:/app sergioisidoro/github-transifex-action:latest 125 | ``` 126 | 127 | For more information, see the [Docker Docs: Docker run reference](https://docs.docker.com/engine/reference/run/). 128 | 129 | Instead of using the latest pre-built Docker image, you can also specify a Docker image tag (which corresponds to the tags [released on GitHub](https://github.com/ergebnis/github-action-template/releases)): 130 | 131 | ```diff 132 | on: 133 | pull_request: 134 | push: 135 | branches: 136 | - master 137 | tags: 138 | - "**" 139 | 140 | name: "Continuous Integration" 141 | 142 | jobs: 143 | github-action-template: 144 | name: github-action-template 145 | 146 | runs-on: ubuntu-latest 147 | 148 | steps: 149 | - name: "Checkout" 150 | uses: actions/checkout@master 151 | 152 | - name: "Run action" 153 | - uses: docker://sergioisidoro/github-transifex-action:latest 154 | + uses: docker://sergioisidoro/github-transifex-action:1.2.3 155 | ``` 156 | 157 | ## Changelog 158 | 159 | Please have a look at [`CHANGELOG.md`](CHANGELOG.md). 160 | 161 | ## Contributing 162 | 163 | 164 | ### TODO: 165 | - Passing the resource as an argument 166 | 167 | Please have a look at [`CONTRIBUTING.md`](.github/CONTRIBUTING.md). 168 | 169 | ## Code of Conduct 170 | 171 | Please have a look at [`CODE_OF_CONDUCT.md`](.github/CODE_OF_CONDUCT.md). 172 | 173 | ## License 174 | 175 | This package is licensed using the MIT License. 176 | 177 | ## Authors and Contributors 178 | - @smaisidoro 179 | - @rGaillard 180 | --------------------------------------------------------------------------------