├── .github ├── FUNDING.yml ├── boring-cyborg.yml ├── renovate.json ├── settings.yml └── workflows │ ├── ci.yml │ ├── craft-release.yaml │ └── set-milestone-on-pr.yaml ├── .vscode └── settings.json ├── LICENSE ├── README.md ├── action.yml ├── examples └── scheduled-release.md ├── images └── output.png └── main.js /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: WyriHaximus -------------------------------------------------------------------------------- /.github/boring-cyborg.yml: -------------------------------------------------------------------------------- 1 | labelPRBasedOnFilePath: 2 | "Dependencies 📦": 3 | - Dockerfile* 4 | - composer.* 5 | - package.json 6 | - package-lock.json 7 | - yarn.lock 8 | "Docker 🐳": 9 | - Dockerfile* 10 | - .docker/**/* 11 | "Image 🖼": 12 | - "**/*.gif" 13 | - "**/*.jpg" 14 | - "**/*.jpeg" 15 | - "**/*.png" 16 | - "**/*.webp" 17 | "CSS 👩‍🎨": 18 | - "**/*.css" 19 | "HTML 👷‍♀️": 20 | - "**/*.htm" 21 | - "**/*.html" 22 | "NEON 🦹‍♂️": 23 | - "**/*.neon" 24 | "MarkDown 📝": 25 | - "**/*.md" 26 | "YAML 🍄": 27 | - "**/*.yml" 28 | - "**/*.yaml" 29 | "JSON 👨‍💼": 30 | - "**/*.json" 31 | "Go 🐹": 32 | - "**/*.go" 33 | "JavaScript 🦏": 34 | - "**/*.js" 35 | - package.json 36 | - package-lock.json 37 | - yarn.lock 38 | "PHP 🐘": 39 | - "**/*.php" 40 | - composer.* 41 | "Configuration ⚙": 42 | - .github/* 43 | "CI 🚧": 44 | - .github/workflows/* 45 | - .scrutinizer.yml 46 | "Templates 🌲": 47 | - "**/*.twig" 48 | - "**/*.tpl" 49 | "Helm ☸": 50 | - .helm/**/* 51 | "Tests 🧪": 52 | - tests/**/* 53 | "Source 🔮": 54 | - src/**/* 55 | 56 | labelerFlags: 57 | labelOnPRUpdates: true 58 | -------------------------------------------------------------------------------- /.github/renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "github>WyriHaximus/renovate-config:github-action" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /.github/settings.yml: -------------------------------------------------------------------------------- 1 | repository: 2 | private: false 3 | has_issues: true 4 | has_wiki: false 5 | has_downloads: true 6 | default_branch: master 7 | allow_squash_merge: false 8 | allow_merge_commit: true 9 | allow_rebase_merge: false 10 | 11 | # Labels: define labels for Issues and Pull Requests 12 | labels: 13 | - name: "Dependencies 📦" 14 | color: 0025ff 15 | description: "Pull requests that update a dependency file" 16 | - name: "Image 🖼" 17 | color: 00ffff 18 | - name: "HTML 👷‍♀️" 19 | color: ffffff 20 | - name: "CSS 👩‍🎨" 21 | color: b3b3b3 22 | - name: "JavaScript 🦏" 23 | color: ffff00 24 | - name: "Go 🐹" 25 | color: 00ADD8 26 | - name: "JSON 👨‍💼" 27 | color: 00ADD8 28 | - name: "NEON 🦹‍♂️" 29 | color: CE3262 30 | - name: "MarkDown 📝" 31 | color: 000000 32 | - name: "YAML 🍄" 33 | color: ff1aff 34 | - name: "Templates 🌲" 35 | color: 009933 36 | - name: "Helm ☸" 37 | color: 091C84 38 | - name: "Tests 🧪" 39 | color: ffe6e6 40 | - name: "Source 🔮" 41 | color: e6ffe6 42 | - name: "Configuration ⚙" 43 | color: b3b3cc 44 | - name: "PHP 🐘" 45 | color: 8892BF 46 | description: "Hypertext Pre Processor" 47 | - name: "Docker 🐳" 48 | color: 0db7ed 49 | description: "Pull requests that relate to Docker" 50 | - name: "CI 🚧" 51 | color: ffff00 52 | - name: "Feature 🏗" 53 | color: 66ff99 54 | - name: "Documentation 📚" 55 | color: 6666ff 56 | - name: "Security 🕵️‍♀️" 57 | color: ff0000 58 | - name: "Hacktoberfest 🎃" 59 | color: 152347 60 | - name: "Bug 🐞" 61 | color: d73a4a 62 | description: "Something isn't working" 63 | oldname: bug 64 | - name: "Duplicate ♊" 65 | color: cfd3d7 66 | description: "This issue or pull request already exists" 67 | oldname: duplicate 68 | - name: "Enhancement ✨" 69 | color: a2eeef 70 | description: "New feature or request" 71 | oldname: enhancement 72 | - name: "Good First Issue" 73 | color: 7057ff 74 | description: "Good for newcomers" 75 | oldname: "good first issue" 76 | - name: "Help Wanted" 77 | color: 008672 78 | description: "Extra attention is needed" 79 | oldname: "help wanted" 80 | - name: Invalid 81 | color: e4e669 82 | description: "This doesn't seem right" 83 | oldname: invalid 84 | - name: "Question ❓" 85 | color: d876e3 86 | description: "Further information is requested" 87 | oldname: question 88 | - name: "Will not be fixed 🛑" 89 | color: ffffff 90 | description: "This will not be worked on" 91 | oldname: wontfix 92 | - name: "Sponsor Request ❤️" 93 | color: fedbf0 94 | description: "Issue/PR opened by sponsor" 95 | 96 | branches: 97 | - name: master 98 | protection: 99 | required_pull_request_reviews: 100 | required_approving_review_count: 1 101 | dismiss_stale_reviews: true 102 | require_code_owner_reviews: true 103 | # Required. Require status checks to pass before merging. Set to null to disable 104 | required_status_checks: 105 | # Required. Require branches to be up to date before merging. 106 | strict: true 107 | # Required. The list of status checks to require in order to merge into this branch 108 | contexts: [] 109 | # Required. Enforce all configured restrictions for administrators. Set to true to enforce required status checks for repository administrators. Set to null to disable. 110 | enforce_admins: true 111 | # Required. Restrict who can push to this branch. Team and user restrictions are only available for organization-owned repositories. Set to null to disable. 112 | restrictions: 113 | apps: [] 114 | users: [] 115 | teams: [] 116 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Continuous Integration 2 | on: 3 | push: 4 | branches: 5 | - 'master' 6 | pull_request: 7 | jobs: 8 | get-previous-tag-with-working-directory: 9 | name: Test Get Previous Tag on ${{ matrix.os }} with Working Directory 10 | strategy: 11 | fail-fast: false 12 | matrix: 13 | os: 14 | - ubuntu-latest 15 | - windows-latest 16 | - macos-latest 17 | runs-on: ${{ matrix.os }} 18 | steps: 19 | - uses: actions/checkout@v4 20 | with: 21 | fetch-depth: 0 # Required due to the way Git works, without it this action won't be able to find any or the correct tags 22 | - uses: actions/checkout@v4 23 | with: 24 | repository: WyriHaximus/php-fake-php-version 25 | ref: master 26 | path: tmp/some/other/path 27 | fetch-depth: 0 # Required due to the way Git works, without it this action won't be able to find any or the correct tags 28 | - name: 'Get Previous tag' 29 | id: previoustag 30 | uses: ./ 31 | with: 32 | workingDirectory: tmp/some/other/path 33 | - run: | 34 | echo "Tag: ${{ steps.previoustag.outputs.tag }}" 35 | echo "Timestamp: ${{ steps.previoustag.outputs.timestamp }}" 36 | test -n "${{ steps.previoustag.outputs.tag }}" 37 | test -n "${{ steps.previoustag.outputs.timestamp }}" 38 | - name: Assert we got the tag 39 | uses: therussiankid92/gat@v1 40 | with: 41 | assertion: should.equal 42 | expected: 1.8.38 43 | actual: ${{ steps.previoustag.outputs.tag }} 44 | get-previous-tag: 45 | name: Test Get Previous Tag on ${{ matrix.os }} 46 | strategy: 47 | fail-fast: false 48 | matrix: 49 | os: 50 | - ubuntu-latest 51 | - windows-latest 52 | - macos-latest 53 | runs-on: ${{ matrix.os }} 54 | steps: 55 | - uses: actions/checkout@v4 56 | with: 57 | fetch-depth: 0 # Required due to the way Git works, without it this action won't be able to find any or the correct tags 58 | - name: 'Get Previous tag' 59 | id: previoustag 60 | uses: ./ 61 | - run: | 62 | echo "Tag: ${{ steps.previoustag.outputs.tag }}" 63 | echo "Timestamp: ${{ steps.previoustag.outputs.timestamp }}" 64 | test -n "${{ steps.previoustag.outputs.tag }}" 65 | test -n "${{ steps.previoustag.outputs.timestamp }}" 66 | - name: Assert we got the tag 67 | uses: therussiankid92/gat@v1 68 | with: 69 | assertion: should.equal 70 | expected: v1 71 | actual: ${{ steps.previoustag.outputs.tag }} 72 | - name: Add tag with prefix 73 | run: | 74 | git tag tag-with-prefix-v1.0.0 75 | - name: 'Get Previous tag with prefix' 76 | id: previoustagwithprefix 77 | uses: ./ 78 | with: 79 | prefix: tag-with-prefix-v 80 | - run: | 81 | echo "Tag: ${{ steps.previoustagwithprefix.outputs.tag }}" 82 | echo "Timestamp: ${{ steps.previoustagwithprefix.outputs.timestamp }}" 83 | test -n "${{ steps.previoustagwithprefix.outputs.tag }}" 84 | test -n "${{ steps.previoustagwithprefix.outputs.timestamp }}" 85 | - name: Remove tags 86 | run: | 87 | rm -r .git/refs/tags 88 | - name: Assert we got the tag with the expected prefix 89 | uses: therussiankid92/gat@v1 90 | with: 91 | assertion: should.equal 92 | expected: tag-with-prefix-v1.0.0 93 | actual: ${{ steps.previoustagwithprefix.outputs.tag }} 94 | - name: 'Get Previous tag with fallback' 95 | id: previoustagwithfallback 96 | uses: ./ 97 | with: 98 | fallback: v1.0.0 99 | - run: | 100 | echo "Tag: ${{ steps.previoustagwithfallback.outputs.tag }}" 101 | echo "Timestamp: ${{ steps.previoustagwithfallback.outputs.timestamp }}" 102 | test -n "${{ steps.previoustagwithfallback.outputs.tag }}" 103 | test -n "${{ steps.previoustagwithfallback.outputs.timestamp }}" 104 | - name: Assert we got the fallback 105 | uses: therussiankid92/gat@v1 106 | with: 107 | assertion: should.equal 108 | expected: v1.0.0 109 | actual: ${{ steps.previoustagwithfallback.outputs.tag }} 110 | -------------------------------------------------------------------------------- /.github/workflows/craft-release.yaml: -------------------------------------------------------------------------------- 1 | name: Create Release 2 | env: 3 | DOCKER_IMAGE: wyrihaximusgithubactions/jwage-changelog-generator 4 | MILESTONE: ${{ github.event.milestone.title }} 5 | on: 6 | milestone: 7 | types: 8 | - closed 9 | jobs: 10 | wait-for-status-checks: 11 | name: Wait for status checks 12 | runs-on: ubuntu-latest 13 | steps: 14 | - run: sleep 13 15 | - name: 'Wait for status checks' 16 | id: waitforstatuschecks 17 | uses: "WyriHaximus/github-action-wait-for-status@master" 18 | with: 19 | ignoreActions: "Wait for status checks" 20 | checkInterval: 5 21 | env: 22 | GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" 23 | - if: steps.waitforstatuschecks.outputs.status != 'success' 24 | name: Fail 25 | run: exit 1 26 | generate-changelog: 27 | name: Generate Changelog 28 | runs-on: ubuntu-latest 29 | needs: 30 | - wait-for-status-checks 31 | outputs: 32 | changelog: ${{ steps.changelog.outputs.changelog }} 33 | steps: 34 | - name: Generate changelog 35 | uses: WyriHaximus/github-action-jwage-changelog-generator@master 36 | id: changelog 37 | env: 38 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 39 | with: 40 | milestone: ${{ env.MILESTONE }} 41 | - name: Show changelog 42 | run: echo "${CHANGELOG}" 43 | env: 44 | CHANGELOG: ${{ steps.changelog.outputs.changelog }} 45 | create-release: 46 | name: Create Release 47 | needs: 48 | - generate-changelog 49 | runs-on: ubuntu-latest 50 | steps: 51 | - uses: actions/checkout@v4 52 | with: 53 | fetch-depth: 0 # Required due to the way Git works, without it this action won't be able to find any or the correct tags 54 | - name: Create release/${{ env.MILESTONE }} branch 55 | run: git checkout -b release/${{ env.MILESTONE }} ${GITHUB_SHA} 56 | - run: echo -e "${CHANGELOG}" > release-${{ env.MILESTONE }}-changelog.md 57 | env: 58 | CHANGELOG: ${{ needs.generate-changelog.outputs.changelog }} 59 | - run: | 60 | echo -e "${MILESTONE_DESCRIPTION}\r\n\r\n${CHANGELOG}" > release-${{ env.MILESTONE }}-release-message.md 61 | cat release-${{ env.MILESTONE }}-release-message.md 62 | release_message=$(cat release-${{ env.MILESTONE }}-release-message.md) 63 | release_message="${release_message//'%'/'%25'}" 64 | release_message="${release_message//$'\n'/'%0A'}" 65 | release_message="${release_message//$'\r'/'%0D'}" 66 | echo "::set-output name=release_message::$release_message" 67 | id: releasemessage 68 | env: 69 | MILESTONE_DESCRIPTION: ${{ github.event.milestone.description }} 70 | CHANGELOG: ${{ needs.generate-changelog.outputs.changelog }} 71 | - name: Create release 72 | uses: actions/create-release@v1 73 | env: 74 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 75 | with: 76 | tag_name: ${{ env.MILESTONE }} 77 | release_name: ${{ env.MILESTONE }} 78 | body: ${{ steps.releasemessage.outputs.release_message }} 79 | draft: false 80 | prerelease: false 81 | - name: Updated related tags 82 | uses: haya14busa/action-update-semver@v1 83 | with: 84 | tag: ${{ env.MILESTONE }} 85 | 86 | -------------------------------------------------------------------------------- /.github/workflows/set-milestone-on-pr.yaml: -------------------------------------------------------------------------------- 1 | name: Set Milestone 2 | on: 3 | pull_request: 4 | types: 5 | - assigned 6 | - opened 7 | - synchronize 8 | - reopened 9 | - edited 10 | - ready_for_review 11 | - review_requested 12 | jobs: 13 | set-milestone: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v4 17 | with: 18 | fetch-depth: 0 # Required due to the way Git works, without it this action won't be able to find any or the correct tags 19 | if: github.event.pull_request.milestone == null 20 | - name: 'Get Previous tag' 21 | if: github.event.pull_request.milestone == null 22 | id: previousgittag 23 | continue-on-error: true 24 | uses: "WyriHaximus/github-action-get-previous-tag@master" 25 | env: 26 | GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" 27 | - run: | 28 | if [ $(echo ${GITTAG} | wc -c) -eq 1 ] ; then 29 | printf "Falling back to v1.0.0 as \"%s\" is unexpectedly empty\r\n" "${GITTAG}" 30 | printf "::set-output name=tag::%s" "v1.0.0" 31 | exit 0 32 | fi 33 | 34 | printf "Using \"%s\"\r\n" "${GITTAG}" 35 | printf "::set-output name=tag::%s" "${GITTAG}" 36 | name: Fall back to v1.0.0 if we haven't tagged anything yet 37 | if: github.event.pull_request.milestone == null 38 | id: previoustag 39 | env: 40 | GITTAG: ${{ steps.previousgittag.outputs.tag }} 41 | - name: 'Get next versions' 42 | if: github.event.pull_request.milestone == null 43 | id: semvers 44 | uses: "WyriHaximus/github-action-next-semvers@master" 45 | with: 46 | version: ${{ steps.previoustag.outputs.tag }} 47 | strict: false 48 | - run: | 49 | if [ "$IS_DEPENDABOT" = true ] ; then 50 | echo "Is dependabot PR" 51 | if [[ "$(printenv MILESTONES | jq -c '. | length')" -eq "0" ]] ; then 52 | echo "No milestone exists, usint patch version for next milestone" 53 | printf "::set-output name=milestone::%s" "${PATCH}" 54 | exit 0 55 | fi 56 | fi 57 | 58 | echo "Using default minor version for next milestone" 59 | printf "::set-output name=milestone::%s" "${MINOR}" 60 | name: Decide which version to use as milestone 61 | if: github.event.pull_request.milestone == null 62 | id: milestone 63 | env: 64 | MILESTONES: ${{ steps.milestones.outputs.milestones }} 65 | MAJOR: ${{ steps.semvers.outputs.v_major }} 66 | MINOR: ${{ steps.semvers.outputs.v_minor }} 67 | PATCH: ${{ steps.semvers.outputs.v_patch }} 68 | IS_DEPENDABOT: ${{ contains(github.ref, 'dependabot') }} 69 | GITTAG: ${{ steps.previousgittag.outputs.tag }} 70 | PREVIOUSTAG: ${{ steps.previoustag.outputs.tag }} 71 | - name: 'Get Milestones' 72 | if: github.event.pull_request.milestone == null 73 | uses: "WyriHaximus/github-action-get-milestones@master" 74 | id: milestones 75 | env: 76 | GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" 77 | - run: printf "::set-output name=number::%s" $(printenv MILESTONES | jq --arg MILESTONE $(printenv MILESTONE) '.[] | select(.title == $MILESTONE) | .number') 78 | if: github.event.pull_request.milestone == null 79 | id: querymilestone 80 | env: 81 | MILESTONES: ${{ steps.milestones.outputs.milestones }} 82 | MILESTONE: ${{ steps.milestone.outputs.milestone }} 83 | - name: 'Create Milestone' 84 | if: github.event.pull_request.milestone == null && steps.querymilestone.outputs.number == '' 85 | id: createmilestone 86 | uses: "WyriHaximus/github-action-create-milestone@master" 87 | with: 88 | title: ${{ steps.milestone.outputs.milestone }} 89 | env: 90 | GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" 91 | - name: 'Select found or created Milestone' 92 | if: github.event.pull_request.milestone == null 93 | id: selectmilestone 94 | run: | 95 | if [ $(echo ${QUERY_NUMBER} | wc -c) -eq 1 ] ; then 96 | printf "::set-output name=number::%s" "${CREATED_NUMBER}" 97 | exit 0 98 | fi 99 | 100 | printf "::set-output name=number::%s" "${QUERY_NUMBER}" 101 | env: 102 | CREATED_NUMBER: ${{ steps.createmilestone.outputs.number }} 103 | QUERY_NUMBER: ${{ steps.querymilestone.outputs.number }} 104 | - name: 'Set Milestone' 105 | if: github.event.pull_request.milestone == null 106 | uses: "WyriHaximus/github-action-set-milestone@master" 107 | with: 108 | issue_number: ${{ github.event.pull_request.number }} 109 | milestone_number: ${{ steps.selectmilestone.outputs.number }} 110 | env: 111 | GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" 112 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "workbench.colorCustomizations": { 3 | "activityBar.activeBackground": "#ad90bc", 4 | "activityBar.activeBorder": "#e7e2d7", 5 | "activityBar.background": "#ad90bc", 6 | "activityBar.foreground": "#15202b", 7 | "activityBar.inactiveForeground": "#15202b99", 8 | "activityBarBadge.background": "#e7e2d7", 9 | "activityBarBadge.foreground": "#15202b", 10 | "tab.activeBorder": "#ad90bc", 11 | "titleBar.activeBackground": "#9670a9", 12 | "titleBar.activeForeground": "#15202b", 13 | "titleBar.inactiveBackground": "#9670a999", 14 | "titleBar.inactiveForeground": "#15202b99" 15 | }, 16 | "peacock.color": "#9670a9" 17 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Cees-Jan Kiewiet 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Get previous tag 2 | 3 | 4 | [![Continuous Integration](https://github.com/WyriHaximus/github-action-get-previous-tag/actions/workflows/ci.yml/badge.svg)](https://github.com/WyriHaximus/github-action-get-previous-tag/actions/workflows/ci.yml) 5 | [![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/WyriHaximus/github-action-get-previous-tag?logo=github&sort=semver)](https://github.com/WyriHaximus/github-action-get-previous-tag/releases) 6 | 7 | 8 | GitHub Action that gets the latest tag from Git 9 | 10 | ![Example output showing this action in action](images/output.png) 11 | 12 | ## Input 13 | 14 | By default, this action will fail if no tag can be found, however, it accepts a `fallback` tag that will be used when no 15 | tag can be found. Keep in mind that when this action is used in a workflow that has no `.git` directory, it will still 16 | fail, and the fallback tag isn't used. It is also accepts a `prefix` string to query the tags based on it. And finally 17 | it takes a `workingDirectory` if you need to look for a tag in an alternative path. 18 | 19 | * `fallback`: `1.0.0` 20 | * `prefix`: `tag-prefix` 21 | * `workingDirectory`: `another/path/where/a/git/repo/is/checked/out` 22 | 23 | ## Output 24 | 25 | This action has two outputs, `tag` for the found tag, or the fallback. And, `timestamp` as a UNIX Epoch timestmap for 26 | when the tag was created, or when no tag is found, and a fallback tag has be specific is provides the timestamp of 27 | action execution. 28 | 29 | * `tag`: `1.2.3` 30 | * `timestamp`: `123` 31 | 32 | ## Example 33 | 34 | Find more examples in the [examples directory](./examples/). 35 | 36 | The following example works together with the [`WyriHaximus/github-action-next-semvers`](https://github.com/marketplace/actions/next-semvers) and [`WyriHaximus/github-action-create-milestone`](https://github.com/marketplace/actions/create-milestone) actions. 37 | Where it provides the previous tag from that action so it can supply a set of versions for the next action, which creates a new milestone. 38 | (This snippet has been taken from the automatic code generation of [`wyrihaximus/fake-php-version`](https://github.com/wyrihaximus/php-fake-php-version/).) 39 | 40 | ```yaml 41 | name: Generate 42 | jobs: 43 | generate: 44 | steps: 45 | - uses: actions/checkout@v3 46 | with: 47 | fetch-depth: 0 # Required due to the way Git works, without it this action won't be able to find any or the correct tags 48 | - name: 'Get Previous tag' 49 | id: previoustag 50 | uses: "WyriHaximus/github-action-get-previous-tag@v1" 51 | with: 52 | fallback: 1.0.0 # Optional fallback tag to use when no tag can be found 53 | #workingDirectory: another/path/where/a/git/repo/is/checked/out # Optional alternative working directory 54 | - name: 'Get next minor version' 55 | id: semvers 56 | uses: "WyriHaximus/github-action-next-semvers@v1" 57 | with: 58 | version: ${{ steps.previoustag.outputs.tag }} 59 | - name: 'Create new milestone' 60 | id: createmilestone 61 | uses: "WyriHaximus/github-action-create-milestone@v1" 62 | with: 63 | title: ${{ steps.semvers.outputs.patch }} 64 | env: 65 | GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" 66 | ``` 67 | 68 | ## License ## 69 | 70 | Copyright 2021 [Cees-Jan Kiewiet](http://wyrihaximus.net/) 71 | 72 | Permission is hereby granted, free of charge, to any person 73 | obtaining a copy of this software and associated documentation 74 | files (the "Software"), to deal in the Software without 75 | restriction, including without limitation the rights to use, 76 | copy, modify, merge, publish, distribute, sublicense, and/or sell 77 | copies of the Software, and to permit persons to whom the 78 | Software is furnished to do so, subject to the following 79 | conditions: 80 | 81 | The above copyright notice and this permission notice shall be 82 | included in all copies or substantial portions of the Software. 83 | 84 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 85 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 86 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 87 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 88 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 89 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 90 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 91 | OTHER DEALINGS IN THE SOFTWARE. 92 | -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | name: 'Get Latest Tag' 2 | description: 'Get the latest tag from git and outputs that for use in other actions' 3 | branding: 4 | icon: 'tag' 5 | color: 'gray-dark' 6 | inputs: 7 | fallback: 8 | description: 'Fallback tag to use when no previous tag can be found' 9 | required: false 10 | prefix: 11 | description: 'Prefix to query the tag by' 12 | required: false 13 | workingDirectory: 14 | description: The directory to run this workflow in 15 | default: "" 16 | required: false 17 | outputs: 18 | tag: 19 | description: 'Latest tag' 20 | timestamp: 21 | description: 'Latest tag timestamp' 22 | runs: 23 | using: 'node20' 24 | main: 'main.js' 25 | -------------------------------------------------------------------------------- /examples/scheduled-release.md: -------------------------------------------------------------------------------- 1 | # Scheduled Release 2 | 3 | This example demonstrates how a release schedule can be limited to only occur if there have been no other releases in the past week. 4 | 5 | ```yaml 6 | name: Scheduled Release 7 | 8 | on: 9 | schedule: 10 | - cron: '0 0 * * 1' # Every Monday at 00:00 AM UTC on the default branch 11 | 12 | jobs: 13 | analyze-tags: 14 | runs-on: ubuntu-latest 15 | outputs: 16 | previous-tag: ${{ steps.previoustag.outputs.tag }} 17 | timestamp-diff: ${{ steps.diff.outputs.timestamp-diff }} 18 | steps: 19 | - uses: actions/checkout@v4 20 | #▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼# 21 | - run: git fetch --tags origin 22 | 23 | - name: Get previous tag 24 | id: previoustag 25 | uses: "WyriHaximus/github-action-get-previous-tag@v1" 26 | #▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲# 27 | - name: Get seconds from previous tag to now 28 | id: diff 29 | shell: bash 30 | env: 31 | TIMESTAMP_TAG: ${{ steps.previoustag.outputs.timestamp }} 32 | run: | 33 | echo "::set-output name=timestamp-diff::$(expr $(printf '%(%s)T') - $TIMESTAMP_TAG)" 34 | 35 | schedule-release: 36 | runs-on: ubuntu-latest 37 | needs: analyze-tags 38 | if: needs.analyze-tags.outputs.timestamp-diff > 604800 # 604800 equal one week. 39 | steps: 40 | - uses: actions/checkout@v2.3.3 41 | with: 42 | token: ${{ secrets.GH_TOKEN }} 43 | - name: Get next minor version 44 | id: semvers 45 | uses: "WyriHaximus/github-action-next-semvers@v1" 46 | with: 47 | version: ${{ needs.analyze-tags.outputs.previous-tag }} 48 | 49 | # Now schedule the release... 50 | 51 | # In the example below, a file is changed 52 | # (the scheduled tag is written to an arbitrary property within a package.json file). 53 | # The following commit would then trigger a semantic release through a following workflow 54 | # (https://github.com/semantic-release/semantic-release) 55 | 56 | - name: manifest Version 57 | uses: deef0000dragon1/json-edit-action/@v1 58 | env: 59 | KEY: scheduleVersion 60 | VALUE: ${{ steps.semvers.outputs.patch }} 61 | FILE: package.json 62 | - uses: stefanzweifel/git-auto-commit-action@v4.5.1 63 | with: 64 | commit_message: 'fix(release): schedule release' 65 | ``` 66 | -------------------------------------------------------------------------------- /images/output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WyriHaximus/github-action-get-previous-tag/a8f2215feac0522ff78eba734c1e91e5b59fb434/images/output.png -------------------------------------------------------------------------------- /main.js: -------------------------------------------------------------------------------- 1 | const { exec } = require('child_process'); 2 | const fs = require('fs'); 3 | const tagPrefix = `${process.env.INPUT_PREFIX || ''}*`; 4 | const workingDirectory = process.env.INPUT_WORKINGDIRECTORY || null; 5 | 6 | console.log('\x1b[33m%s\x1b[0m', 'Working directory: ', workingDirectory || ''); 7 | 8 | exec(`git for-each-ref --sort=-creatordate --count 1 --format="%(refname:short)" "refs/tags/${tagPrefix}"`, {cwd: workingDirectory}, (err, tag, stderr) => { 9 | tag = tag.trim(); 10 | 11 | if (err) { 12 | console.log('\x1b[33m%s\x1b[0m', 'Could not find any tags because: '); 13 | console.log('\x1b[31m%s\x1b[0m', stderr); 14 | process.exit(1); 15 | } else if (tag === "") { 16 | let timestamp = Math.floor(new Date().getTime() / 1000); 17 | console.log('\x1b[33m%s\x1b[0m', 'Falling back to default tag'); 18 | console.log('\x1b[32m%s\x1b[0m', `Found tag: ${process.env.INPUT_FALLBACK}`); 19 | console.log('\x1b[32m%s\x1b[0m', `Found timestamp: ${timestamp}`); 20 | fs.appendFileSync(process.env.GITHUB_OUTPUT, `tag=${process.env.INPUT_FALLBACK}\n`); 21 | fs.appendFileSync(process.env.GITHUB_OUTPUT, `timestamp=${timestamp}\n`); 22 | process.exit(0); 23 | } 24 | 25 | exec(`git log -1 --format=%at ${tag}`, {cwd: workingDirectory}, (err, timestamp, stderr) => { 26 | if (err) { 27 | console.log('\x1b[33m%s\x1b[0m', 'Could not find any timestamp because: '); 28 | console.log('\x1b[31m%s\x1b[0m', stderr); 29 | process.exit(1); 30 | } 31 | 32 | timestamp = timestamp.trim(); 33 | 34 | console.log('\x1b[32m%s\x1b[0m', `Found tag: ${tag}`); 35 | console.log('\x1b[32m%s\x1b[0m', `Found timestamp: ${timestamp}`); 36 | fs.appendFileSync(process.env.GITHUB_OUTPUT, `tag=${tag}\n`); 37 | fs.appendFileSync(process.env.GITHUB_OUTPUT, `timestamp=${timestamp}\n`); 38 | process.exit(0); 39 | }); 40 | }); 41 | --------------------------------------------------------------------------------