diff --git a/.github/workflows/automated-release.yml b/.github/workflows/automated-release.yml new file mode 100644 index 00000000..631ae2ca --- /dev/null +++ b/.github/workflows/automated-release.yml @@ -0,0 +1,123 @@ +name: Automated Release + +on: + push: + branches: + - main + paths: + - "pyproject.toml" + +env: + REGISTRY: github-standards-hooks + +jobs: + verify-release-version: + runs-on: ubuntu-latest + permissions: + contents: read + + outputs: + tag: ${{ steps.version.outputs.tag }} + version: ${{ steps.version.outputs.version }} + requires_release: ${{ steps.version.outputs.requires_release }} + + steps: + - name: Checkout repository + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 + with: + fetch-depth: 0 + fetch-tags: true + + - name: Set up Python + uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 + with: + python-version-file: ".python-version" + + - name: Extract version + id: extract_version + shell: python + run: | + import os + import tomllib + with open("pyproject.toml", "rb") as f: + contents = tomllib.load(f) + version = contents["project"]["version"] + with open(os.environ['GITHUB_OUTPUT'], 'a') as fh: + fh.write(f"version={version}\n") + + - name: Validate we're on main branch + run: | + current_branch=$(git branch --show-current) + if [ "$current_branch" != "main" ]; then + echo "Error: Must be on main branch" + exit 1 + fi + + - name: Process version and tag + id: version + shell: bash + run: | + input_version="${{ steps.extract_version.outputs.version }}" + clean_version=${input_version#v} + + # Validate version format + if ! echo "$clean_version" | grep -E '^[0-9]+\.[0-9]+\.[0-9]+$'; then + echo "Error: Version must be in format x.x.x (with or without v prefix)" + exit 1 + fi + + git_tag="v$clean_version" + requires_release="true" + + # Check if tag already exists + if [ $(git tag -l "$git_tag") ]; then + echo "Tag $git_tag already exists" + requires_release="false" + fi + + echo "version=$clean_version" >> $GITHUB_OUTPUT + echo "tag=$git_tag" >> $GITHUB_OUTPUT + echo "requires_release=$requires_release" >> $GITHUB_OUTPUT + echo "Clean version: $clean_version" + echo "Git tag: $git_tag" + echo "Requires release: $requires_release" + + # This is a workaround to allow us to pass variables to the push-to-ecr reusable workflow. As that workflow runs in + # a separate github runner, the env vars in this file are not available + setup: + needs: [verify-release-version] + if: ${{ needs.verify-release-version.outputs.requires_release == 'true' }} + runs-on: ubuntu-latest + permissions: + contents: read + outputs: + REGISTRY: ${{ env.REGISTRY }} + steps: + - run: echo "All set!" + + build-and-push-latest-image: + needs: [setup, verify-release-version] + permissions: + contents: read + id-token: write + packages: write + attestations: write + uses: ./.github/workflows/build-and-push-to-ghcr.yml + with: + image_tags: latest,${{ needs.verify-release-version.outputs.tag }} + secrets: inherit + + create-github-release: + needs: [setup, verify-release-version, build-and-push-latest-image] + runs-on: ubuntu-latest + permissions: + contents: write + + steps: + - name: Create tag and GitHub release + uses: ncipollo/release-action@b7eabc95ff50cbeeedec83973935c8f306dfcd0b + with: + tag: ${{ needs.verify-release-version.outputs.tag }} + name: ${{ needs.verify-release-version.outputs.tag }} + generateReleaseNotes: true + makeLatest: true diff --git a/.github/workflows/create-release.yml b/.github/workflows/create-release.yml deleted file mode 100644 index d598aab8..00000000 --- a/.github/workflows/create-release.yml +++ /dev/null @@ -1,38 +0,0 @@ -name: Create Release - -on: - push: - branches: ["main"] - workflow_dispatch: - -permissions: - contents: write - pull-requests: write - -jobs: - create-release: - runs-on: ubuntu-latest - outputs: - tag: ${{ steps.release.outputs.tag_name }} - release_created: ${{ steps.release.outputs.release_created }} - steps: - - uses: googleapis/release-please-action@16a9c90856f42705d54a6fda1823352bdc62cf38 - id: release - with: - token: ${{ secrets.GITHUB_TOKEN }} - release-type: python - config-file: .release-please-config.json - manifest-file: .release-please-manifest.json - - build-and-push-latest-image: - needs: [create-release] - if: ${{ needs.create-release.outputs.release_created }} - permissions: - contents: read - id-token: write - packages: write - attestations: write - uses: ./.github/workflows/build-and-push-to-ghcr.yml - with: - image_tags: latest,${{ needs.create-release.outputs.tag }} - secrets: inherit diff --git a/.release-please-config.json b/.release-please-config.json deleted file mode 100644 index 98037f7e..00000000 --- a/.release-please-config.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "release-type": "python", - "include-v-in-tag": true, - "skip-github-release": false, - "skip-github-pull-request": false, - "packages": { - ".": { - "release-type": "python", - "pull-request-header": ":robot: Next release", - "pull-request-footer": " ", - "extra-files": [ - { - "path": "uv.lock", - "type": "toml", - "jsonpath": "$.package[?(@.name.value=='github-standards')].version" - }, - { - "path": "pyproject.toml", - "type": "toml", - "jsonpath": "$.project.version" - } - ] - } - } -} diff --git a/.release-please-manifest.json b/.release-please-manifest.json deleted file mode 100644 index 6fde7bb7..00000000 --- a/.release-please-manifest.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - ".": "v1.3.1" -} diff --git a/README.md b/README.md index d7f170df..369019e6 100644 --- a/README.md +++ b/README.md @@ -79,14 +79,16 @@ The commit-msg hook stage is passes a single parameter, which is the name of the # Releasing -We are using the release-please GitHub action for controlling releases. A detailed description can be found on the release-please [documentation page](https://github.com/googleapis/release-please). +There is a github workflow that will automatically create a new docker tag, and a github release when a change to the `version` tag inside the `pyproject.toml` file is detected. When a new version needs to be released: -Any PR merges into the main branch will trigger the creation/update of a release-please managed release PR. This PR can be merged at anytime and will: +1. Open the `pyproject.toml` file, and update the `version` tag to a new value. We use semantic versioning, see [this article](https://www.geeksforgeeks.org/software-engineering/introduction-semantic-versioning/) for help determining what the new version value should be +2. Run `uv sync` to ensure the package is set to the correct version +3. Open a PR into main. Once approved, merging will trigger a new release -- Create a new github release with the next semantic version -- Update the pyproject.toml file with the latest version -- Update the .release-please-manifest.json file with the latest version -- Build and deploy a new docker image +You will now have: + +- A github release using the new version, set to the be the latest version +- A docker image build and deployed to our [container registry](https://github.com/uktrade/github-standards/pkgs/container/github-standards) # Usage