├── .github
├── CODEOWNERS
├── release-drafter.yml
├── dependabot.yml
└── workflows
│ └── release-drafter.yml
├── .gitignore
├── .dockerignore
├── docker
├── favicon.ico
├── default.conf
└── index.html
├── Jenkinsfile_k8s
├── compose.yml
├── Makefile
├── Dockerfile
├── LICENSE
├── README.md
└── bin
└── redirects.sh
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | * @jenkins-infra/core
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | jira-keys-to-github-id-for-external-use*
2 | update.sh
3 |
4 |
--------------------------------------------------------------------------------
/.dockerignore:
--------------------------------------------------------------------------------
1 | *
2 | !bin/redirects.sh
3 | !mappings/jira_keys_to_github_ids.txt
4 | !docker/*
5 |
--------------------------------------------------------------------------------
/.github/release-drafter.yml:
--------------------------------------------------------------------------------
1 | _extends: .github
2 |
3 | name-template: 'next'
4 | tag-template: 'next'
5 |
--------------------------------------------------------------------------------
/docker/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jenkins-infra/docker-issue-redirect/main/docker/favicon.ico
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | ---
2 | version: 2
3 | updates:
4 | - package-ecosystem: "github-actions"
5 | directory: "/"
6 | schedule:
7 | interval: "daily"
8 |
--------------------------------------------------------------------------------
/Jenkinsfile_k8s:
--------------------------------------------------------------------------------
1 | buildDockerAndPublishImage('issue-redirect', [
2 | publishToPrivateAzureRegistry: true,
3 | targetplatforms: 'linux/amd64,linux/arm64',
4 | ])
5 |
--------------------------------------------------------------------------------
/compose.yml:
--------------------------------------------------------------------------------
1 | services:
2 | app:
3 | build:
4 | context: .
5 | ports:
6 | - "8060:80"
7 | volumes:
8 | - "./docker/index.html:/htdocs/index.html"
9 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | IMAGE_NAME=$(notdir $(CURDIR))-app
2 |
3 | .PHONY: up down clean
4 |
5 | up:
6 | docker compose -f compose.yml up -d --build
7 |
8 | down:
9 | docker compose -f compose.yml down -v
10 |
11 | clean: down
12 | docker rmi $(IMAGE_NAME) || true
13 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM bash:5.3.8-alpine3.22 AS builder
2 |
3 | WORKDIR /
4 |
5 | COPY . .
6 | RUN ./bin/redirects.sh
7 |
8 | FROM nginx:1.29.3-alpine
9 |
10 | RUN mkdir -p /etc/nginx/includes
11 |
12 | COPY --from=builder jira-to-github-redirects.conf /etc/nginx/includes/jira-to-github-redirects.conf
13 |
14 | COPY docker/favicon.ico /htdocs/favicon.ico
15 | COPY docker/default.conf /etc/nginx/conf.d/default.conf
16 | COPY docker/index.html /htdocs/index.html
17 |
--------------------------------------------------------------------------------
/docker/default.conf:
--------------------------------------------------------------------------------
1 | server {
2 | listen 80;
3 | server_name _ localhost;
4 |
5 | root /htdocs;
6 |
7 | # Exact generated redirects
8 | include includes/jira-to-github-redirects.conf;
9 |
10 | # Generic fallback rewrites
11 | rewrite ^/issue/([0-9]+)$ https://issues.jenkins.io/browse/JENKINS-$1 permanent;
12 | rewrite ^/issue/([A-Z]+-[0-9]+)$ https://issues.jenkins.io/browse/$1 permanent;
13 | rewrite ^/([A-Z]+-[0-9]+)$ https://issues.jenkins.io/browse/$1 permanent;
14 | rewrite ^/browse/([A-Z]+-[0-9]+)$ https://issues.jenkins.io/browse/$1 permanent;
15 |
16 | return 404;
17 | }
18 |
--------------------------------------------------------------------------------
/.github/workflows/release-drafter.yml:
--------------------------------------------------------------------------------
1 | name: Release Drafter
2 | on:
3 | push:
4 | workflow_dispatch:
5 | release:
6 | # Only allow 1 release-drafter build at a time to avoid creating multiple "next" releases
7 | concurrency: "release-drafter"
8 | jobs:
9 | deploy:
10 | runs-on: ubuntu-latest
11 | steps:
12 | - name: Check out
13 | uses: actions/checkout@v6
14 | with:
15 | fetch-depth: 0
16 | - name: Release Drafter
17 | uses: release-drafter/release-drafter@b1476f6e6eb133afa41ed8589daba6dc69b4d3f5 # v6.1.0
18 | with:
19 | name: next
20 | tag: next
21 | version: next
22 | env:
23 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
24 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License
2 |
3 | Copyright (c) 2025-, Jenkins project contributors
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
13 | all 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
21 | THE SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # docker-issue-redirect
2 |
3 | A simple service for redirecting issues to GitHub if they've been migrated or Jira if they haven't been.
4 |
5 | The script [redirect.sh](./bin/redirects.sh) takes a file [jira_keys_to_github_ids.txt](./mappings/jira_keys_to_github_ids.txt) and generates nginx redirect directives.
6 |
7 | A default rule will redirect any unknown issue IDs to Jira.
8 |
9 | ## API
10 |
11 | - `GET /browse/:jira_key` - Redirects to the corresponding GitHub issue, if found. Otherwise to Jira.
12 | - `GET /:jira_key` - Redirects to the corresponding GitHub issue, if found. Otherwise to Jira. (Kept for compatibility with existing uses)
13 | - `GET /issue/:jira_key_id` - Redirects to the corresponding GitHub issue, if found. Otherwise to Jira prefixing it with `JENKINS-`. (Kept for compatibility with existing uses)
14 |
15 | Ex:
16 | - `https://issue-redirect.jenkins.io/JENKINS-1`
17 | - `https://issue-redirect.jenkins.io/INFRA-1`
18 | - `https://issue-redirect.jenkins.io/issue/1`
19 |
20 | ## Adding more
21 |
22 | To add more Jira redirects send a pull request to [jira_keys_to_github_ids.txt](./mappings/jira_keys_to_github_ids.txt).
23 |
24 | To add redirections for issues of another Jira project than the ones already included, you'll also have to update [redirect.sh](./redirect.sh)
25 |
--------------------------------------------------------------------------------
/bin/redirects.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -euo pipefail
4 |
5 | REDIRECTS_FILE="jira-to-github-redirects.conf"
6 |
7 | MAPPINGS_FILE="mappings/jira_keys_to_github_ids.txt"
8 |
9 | # Clear or create the redirects file
10 | > "$REDIRECTS_FILE"
11 |
12 | # Process each line
13 | while IFS=: read -r jira_key github_ref; do
14 | # JENKINS project
15 | if [[ $jira_key =~ JENKINS-([0-9]+) ]]; then
16 | issue_num="${BASH_REMATCH[1]}"
17 |
18 | # Extract the repo path and issue number from github_ref (e.g., jenkinsci/jenkins#13336)
19 | if [[ $github_ref =~ (.+)#([0-9]+) ]]; then
20 | repo_path="${BASH_REMATCH[1]}"
21 | github_issue="${BASH_REMATCH[2]}"
22 |
23 | {
24 | echo "rewrite ^/issue/$issue_num$ https://github.com/$repo_path/issues/$github_issue permanent;"
25 | echo "rewrite ^/issue/JENKINS-$issue_num$ https://github.com/$repo_path/issues/$github_issue permanent;"
26 | echo "rewrite ^/JENKINS-$issue_num$ https://github.com/$repo_path/issues/$github_issue permanent;"
27 | echo "rewrite ^/browse/JENKINS-$issue_num$ https://github.com/$repo_path/issues/$github_issue permanent;"
28 | } >> "$REDIRECTS_FILE"
29 | fi
30 | fi
31 | # INFRA project
32 | if [[ $jira_key =~ INFRA-([0-9]+) ]]; then
33 | issue_num="${BASH_REMATCH[1]}"
34 |
35 | # Extract the repo path and issue number from github_ref (e.g., jenkins-infra/helpdesk#83
36 | if [[ $github_ref =~ (.+)#([0-9]+) ]]; then
37 | repo_path="${BASH_REMATCH[1]}"
38 | github_issue="${BASH_REMATCH[2]}"
39 |
40 | {
41 | echo "rewrite ^/INFRA-$issue_num$ https://github.com/$repo_path/issues/$github_issue permanent;"
42 | echo "rewrite ^/issue/INFRA-$issue_num$ https://github.com/$repo_path/issues/$github_issue permanent;"
43 | echo "rewrite ^/browse/INFRA-$issue_num$ https://github.com/$repo_path/issues/$github_issue permanent;"
44 | } >> "$REDIRECTS_FILE"
45 | fi
46 | fi
47 | done < "$MAPPINGS_FILE"
48 |
49 | echo "Redirects file generated at $REDIRECTS_FILE"
50 |
51 |
--------------------------------------------------------------------------------
/docker/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Issue tracker redirector
8 |
9 |
10 |
11 |
12 |
13 | Issue tracker redirector
14 |
15 | API:
16 |
17 | GET /browse/:jira_key - Redirects to the corresponding GitHub issue, if found. Otherwise to Jira. (Recommended, other routes are kept for compatibility reason)
18 | GET /:jira_key - Redirects to the corresponding GitHub issue, if found. Otherwise to Jira.
19 | GET /issue/:jira_key_id - Redirects to the corresponding GitHub issue, if found. Otherwise to Jira prefixing it with JENKINS-.
20 |
21 |
22 | Example of usage:
23 |
24 | From a Jira link like issues .jenkins.io/browse/JENKINS-1 , replace its subdomain by issue-redirect: issue-redirect .jenkins.io/browse/JENKINS-1
25 |
26 |
27 | To add more Jira redirects send a pull request to jira_keys_to_github_ids.txt .
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------