From 90161ac962ad8692a25b27f6a686f372b2f8dc3f Mon Sep 17 00:00:00 2001 From: Toby Jennings Date: Fri, 20 Dec 2024 10:28:57 -0600 Subject: [PATCH] chore: Refactor Github Actions --- .github/README.md | 38 ++++++++++++++++ .github/dependabot.yml | 11 ----- .github/workflows/build_and_push.yaml | 52 ++++++++++++++++++++++ .github/workflows/ci.yaml | 49 +++++++++++---------- .github/workflows/release.yaml | 63 +++++++++++++++++++++++++++ 5 files changed, 179 insertions(+), 34 deletions(-) create mode 100644 .github/README.md delete mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/build_and_push.yaml create mode 100644 .github/workflows/release.yaml diff --git a/.github/README.md b/.github/README.md new file mode 100644 index 000000000..2fa1b32fa --- /dev/null +++ b/.github/README.md @@ -0,0 +1,38 @@ +# CM-Service Github Workflows + +The GitHub Actions Workflows in this repository enable a CI pattern for managing +service releases. + +1. Any push to an active branch should trigger linting, typing, and testing jobs. +1. Any active "ticket" branch should trigger an OCI image build and push, so the work may be deployed to a dev or staging environment. +1. Any PR merged to `main` should trigger a "release", which should include bumping the project version and writing a Git tag. +1. Any new tags pushed to the repo should trigger an OCI image build and push, so the work may be deployed to a production environment. + +## Flowchart + +```mermaid +flowchart LR + A[GitHub Actions Event] + B{Tag or Branch?} + BM{Merged PR?} + BP([Build+Push]) + C[Lint+Type+Test] + Release[Release] + Ver([Bump Version]) + Tag([Write Tag]) + + A -->|Push/Tag/PR| B + B -->|Branch/PR| BM + B -->|Tag| BP + BM -->|No| C + BM -->|Yes| Release + Release --> Ver + Ver --> Tag + Tag -->|workflow_dispatch| A + C -->|ticket?| BP +``` + +## Notes + +Github Events are not generated by actions initiated using a `GITHUB_TOKEN`, e.g., a workflow that pushes to the repo does not itself cause a `push` event. +For this reason, the `build_and_push` workflow is explicitly triggered by the `release` workflow using a `workflow_dispatch` action. diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index dfb90b728..000000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,11 +0,0 @@ -version: 2 -updates: - - package-ecosystem: "github-actions" - directory: "/" - schedule: - interval: "weekly" - - - package-ecosystem: "docker" - directory: "/" - schedule: - interval: "weekly" diff --git a/.github/workflows/build_and_push.yaml b/.github/workflows/build_and_push.yaml new file mode 100644 index 000000000..70e23c400 --- /dev/null +++ b/.github/workflows/build_and_push.yaml @@ -0,0 +1,52 @@ +# A workflow that builds and (optionally) pushes the Docker container image +# artifacts for the application. The build action occurs on pull request events +# that target the `main` branch, and the push action occurs only with tagged releases +# and ticket branches. +--- +name: "Build and Push" + +"on": + pull_request: + branches: + - main + paths: + - 'src/lsst/cmservice/**' + push: + tags: + - "*" + workflow_dispatch: + +jobs: + ci: + uses: + ./.github/workflows/ci.yaml + + build: + name: "Build and Push Application Container Images" + needs: + - ci + runs-on: ubuntu-latest + timeout-minutes: 20 + + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - uses: lsst-sqre/build-and-push-to-ghcr@v1 + id: build-service + with: + dockerfile: docker/Dockerfile + target: cmservice + image: ${{ github.repository }} + github_token: ${{ secrets.GITHUB_TOKEN }} + push: ${{ github.ref_type == 'tag' || (github.ref_type == 'branch' && startsWith(github.ref_name, 'tickets/DM-')) }} + + - uses: lsst-sqre/build-and-push-to-ghcr@v1 + id: build-worker + with: + dockerfile: docker/Dockerfile + target: cmworker + image: ${{ github.repository }} + github_token: ${{ secrets.GITHUB_TOKEN }} + push: ${{ github.ref_type == 'tag' || (github.ref_type == 'branch' && startsWith(github.ref_name, 'tickets/DM-')) }} diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 831bfd6c3..71d26bf4e 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -1,19 +1,24 @@ +# CI workflow runs linting, typing, and unit tests on every push to a branch +# and when called from another workflow. +--- name: "CI" - -on: +"on": + workflow_call: push: - pull_request: branches: - - main - workflow_dispatch: + - "tickets/**" + - "u/**" -jobs: +env: + UV_FROZEN: "1" +jobs: lint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - name: Checkout Repository + uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v5 @@ -30,16 +35,14 @@ jobs: python-version: ["3.11"] steps: - - uses: actions/checkout@v4 + - name: Checkout Repository + uses: actions/checkout@v4 - name: Install uv - uses: astral-sh/setup-uv@v3 + uses: astral-sh/setup-uv@v5 with: version: "0.5.x" - - - name: Set up Python - uses: actions/setup-python@v5 - with: + enable_cache: true python-version: ${{ matrix.python-version }} - name: Install packages for testing @@ -52,23 +55,23 @@ jobs: mypy: runs-on: ubuntu-latest - steps: + strategy: + matrix: + python-version: ["3.11"] - - uses: actions/checkout@v4 + steps: + - name: Checkout Repository + uses: actions/checkout@v4 - name: Install uv - uses: astral-sh/setup-uv@v3 + uses: astral-sh/setup-uv@v5 with: version: "0.5.x" - - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: "3.11" + enable_cache: true + python-version: ${{ matrix.python-version }} - name: Install packages for testing run: uv sync --dev --frozen - name: Run tests - run: | - uv run make typing + run: uv run make typing diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 000000000..6efbf8ec6 --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,63 @@ +# Workflow makes a new release on demand or when a pull request is merged to main. +# The release consists of bumping the version of the application, creating a +# tag, committing and pushing these changes. +--- +name: "Make Release" + +on: + pull_request: + types: + - closed + branches: + - main + +env: + GIT_USERNAME: github_actions[bot] + GIT_USEREMAIL: 41898282+github_actions[bot]@users.noreply.github.com + +jobs: + release: + runs-on: ubuntu-latest + timeout-minutes: 10 + if: >- + github.event_name == 'pull_request' + && github.event.action == 'closed' + && github.event.pull_request.merged == true + steps: + + - name: Checkout Repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + ref: ${{ github.sha }} + + - name: Force correct release branch + run: git checkout -B ${{ github.ref_name }} ${{ github.sha }} + + - name: Make Release + id: release + uses: python-semantic-release/python-semantic-release@v9.15.2 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + git_committer_name: ${{ env.GIT_USERNAME}} + git_committer_email: ${{ env.GIT_USEREMAIL}} + build: false + changelog: false + vcs_release: false + + # The release step pushes a new tag, but this won't trigger any new workflows + # instead, we manually trigger the build-push workflow after a release is made. + - name: Trigger Build-Push Workflow + uses: actions/github-script@v7 + if: >- + steps.release.outputs.released == 'true' + env: + TAG_REF: ${{ steps.release.outputs.tag }} + with: + script: | + github.rest.actions.createWorkflowDispatch({ + owner: context.repo.owner, + repo: context.repo.repo, + workflow_id: 'build_and_push.yaml', + ref: `${ process.env.TAG_REF }` + })