Skip to content

Commit f3d40e8

Browse files
committed
Initial production-ready jira cli
0 parents  commit f3d40e8

170 files changed

Lines changed: 19316 additions & 0 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/dependabot.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
version: 2
2+
updates:
3+
- package-ecosystem: cargo
4+
directory: /
5+
schedule:
6+
interval: weekly
7+
- package-ecosystem: github-actions
8+
directory: /
9+
schedule:
10+
interval: weekly

.github/workflows/ci.yml

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
permissions:
10+
contents: read
11+
12+
concurrency:
13+
group: ci-${{ github.workflow }}-${{ github.ref }}
14+
cancel-in-progress: true
15+
16+
env:
17+
CARGO_TERM_COLOR: always
18+
RUST_BACKTRACE: 1
19+
RUSTFLAGS: -D warnings
20+
21+
jobs:
22+
workflow-lint:
23+
name: Workflow Lint
24+
runs-on: ubuntu-latest
25+
steps:
26+
- uses: actions/checkout@v4
27+
- name: Run actionlint
28+
uses: docker://rhysd/actionlint:1.7.7
29+
with:
30+
args: -color
31+
32+
fmt:
33+
name: Format
34+
runs-on: ubuntu-latest
35+
steps:
36+
- uses: actions/checkout@v4
37+
- uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 # stable
38+
with:
39+
toolchain: stable
40+
components: rustfmt
41+
- run: cargo fmt --all -- --check
42+
43+
clippy:
44+
name: Clippy
45+
runs-on: ubuntu-latest
46+
steps:
47+
- uses: actions/checkout@v4
48+
- uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 # stable
49+
with:
50+
toolchain: stable
51+
components: clippy
52+
- uses: actions/cache@v4
53+
with:
54+
path: |
55+
~/.cargo/registry
56+
~/.cargo/git
57+
target
58+
key: ${{ runner.os }}-cargo-clippy-${{ hashFiles('**/Cargo.lock') }}
59+
restore-keys: ${{ runner.os }}-cargo-clippy-
60+
- run: cargo clippy --all-targets --all-features -- -D warnings
61+
62+
test:
63+
name: Test (${{ matrix.os }})
64+
runs-on: ${{ matrix.os }}
65+
needs: [fmt, clippy]
66+
strategy:
67+
fail-fast: false
68+
matrix:
69+
os: [ubuntu-latest, macos-latest, windows-latest]
70+
steps:
71+
- uses: actions/checkout@v4
72+
- uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 # stable
73+
with:
74+
toolchain: stable
75+
- uses: actions/cache@v4
76+
with:
77+
path: |
78+
~/.cargo/registry
79+
~/.cargo/git
80+
target
81+
key: ${{ runner.os }}-cargo-test-${{ hashFiles('**/Cargo.lock') }}
82+
restore-keys: ${{ runner.os }}-cargo-test-
83+
- run: cargo test --all-targets --all-features
84+
85+
release-smoke:
86+
name: Release Smoke
87+
runs-on: ubuntu-latest
88+
needs: [fmt, clippy]
89+
steps:
90+
- uses: actions/checkout@v4
91+
- uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 # stable
92+
with:
93+
toolchain: stable
94+
- uses: actions/cache@v4
95+
with:
96+
path: |
97+
~/.cargo/registry
98+
~/.cargo/git
99+
target
100+
key: ${{ runner.os }}-cargo-release-smoke-${{ hashFiles('**/Cargo.lock') }}
101+
restore-keys: ${{ runner.os }}-cargo-release-smoke-
102+
- run: cargo build --release
103+
- run: |
104+
./target/release/jira --version | grep -E '^jira [0-9]+\.[0-9]+\.[0-9]+'
105+
./target/release/jira --help > /dev/null
106+
mkdir -p /tmp/jira-man
107+
./target/release/jira completions man --dir /tmp/jira-man
108+
test -s /tmp/jira-man/jira.1
109+
test "$(find /tmp/jira-man -name '*.1' | wc -l)" -ge 50
110+
111+
audit:
112+
name: Security Audit
113+
runs-on: ubuntu-latest
114+
steps:
115+
- uses: actions/checkout@v4
116+
- uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 # stable
117+
with:
118+
toolchain: stable
119+
- uses: actions/cache@v4
120+
with:
121+
path: |
122+
~/.cargo/registry
123+
~/.cargo/git
124+
~/.cargo/bin/cargo-audit
125+
key: ${{ runner.os }}-cargo-audit-${{ hashFiles('**/Cargo.lock') }}
126+
restore-keys: ${{ runner.os }}-cargo-audit-
127+
- run: command -v cargo-audit >/dev/null || cargo install cargo-audit
128+
- run: cargo audit
129+
130+
ci-complete:
131+
name: CI Complete
132+
runs-on: ubuntu-latest
133+
needs: [workflow-lint, fmt, clippy, test, release-smoke, audit]
134+
if: always()
135+
steps:
136+
- run: |
137+
if [ "${{ needs.workflow-lint.result }}" != "success" ] || \
138+
[ "${{ needs.fmt.result }}" != "success" ] || \
139+
[ "${{ needs.clippy.result }}" != "success" ] || \
140+
[ "${{ needs.test.result }}" != "success" ] || \
141+
[ "${{ needs.release-smoke.result }}" != "success" ] || \
142+
[ "${{ needs.audit.result }}" != "success" ]; then
143+
exit 1
144+
fi
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
name: Jira Cloud Smoke
2+
3+
on:
4+
workflow_dispatch:
5+
6+
permissions:
7+
contents: read
8+
9+
concurrency:
10+
group: jira-cloud-smoke
11+
cancel-in-progress: false
12+
13+
env:
14+
CARGO_TERM_COLOR: always
15+
RUST_BACKTRACE: 1
16+
RUSTFLAGS: -D warnings
17+
JIRA_SMOKE_SITE: ${{ secrets.JIRA_SMOKE_SITE }}
18+
JIRA_SMOKE_EMAIL: ${{ secrets.JIRA_SMOKE_EMAIL }}
19+
JIRA_SMOKE_TOKEN: ${{ secrets.JIRA_SMOKE_TOKEN }}
20+
JIRA_SMOKE_PROJECT: ${{ secrets.JIRA_SMOKE_PROJECT }}
21+
JIRA_SMOKE_ISSUE_TYPE: ${{ vars.JIRA_SMOKE_ISSUE_TYPE }}
22+
JIRA_SMOKE_BOARD_ID: ${{ vars.JIRA_SMOKE_BOARD_ID }}
23+
24+
jobs:
25+
smoke:
26+
name: Jira Cloud Sandbox Smoke
27+
runs-on: ubuntu-latest
28+
steps:
29+
- uses: actions/checkout@v4
30+
- uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 # stable
31+
with:
32+
toolchain: stable
33+
- uses: actions/cache@v4
34+
with:
35+
path: |
36+
~/.cargo/registry
37+
~/.cargo/git
38+
target
39+
key: ${{ runner.os }}-cargo-jira-cloud-smoke-${{ hashFiles('**/Cargo.lock') }}
40+
restore-keys: ${{ runner.os }}-cargo-jira-cloud-smoke-
41+
- run: cargo build --release
42+
- name: Run sandbox smoke
43+
shell: bash
44+
run: |
45+
set -euo pipefail
46+
47+
for name in JIRA_SMOKE_SITE JIRA_SMOKE_EMAIL JIRA_SMOKE_TOKEN JIRA_SMOKE_PROJECT; do
48+
if [ -z "${!name:-}" ]; then
49+
echo "::error::$name must be configured as a repository secret for Jira Cloud smoke tests."
50+
exit 1
51+
fi
52+
done
53+
54+
ISSUE_TYPE="${JIRA_SMOKE_ISSUE_TYPE:-Task}"
55+
CONFIG="${RUNNER_TEMP}/jira-smoke-config.toml"
56+
JIRA=(./target/release/jira --config "$CONFIG" --output json --compact --no-input)
57+
ISSUE_KEY=""
58+
59+
cleanup() {
60+
if [ -n "$ISSUE_KEY" ]; then
61+
"${JIRA[@]}" issue delete "$ISSUE_KEY" --yes || true
62+
fi
63+
}
64+
trap cleanup EXIT
65+
66+
"${JIRA[@]}" config init \
67+
--site "$JIRA_SMOKE_SITE" \
68+
--email "$JIRA_SMOKE_EMAIL" \
69+
--default-project "$JIRA_SMOKE_PROJECT" \
70+
--force
71+
"${JIRA[@]}" auth setup-token --token "$JIRA_SMOKE_TOKEN"
72+
"${JIRA[@]}" auth doctor
73+
"${JIRA[@]}" user current
74+
"${JIRA[@]}" project view "$JIRA_SMOKE_PROJECT"
75+
"${JIRA[@]}" field list --max 25
76+
"${JIRA[@]}" cache refresh projects
77+
"${JIRA[@]}" cache refresh fields
78+
"${JIRA[@]}" completions dynamic project "$JIRA_SMOKE_PROJECT" --values-only
79+
80+
CREATE_JSON=$("${JIRA[@]}" issue create \
81+
--project "$JIRA_SMOKE_PROJECT" \
82+
--type "$ISSUE_TYPE" \
83+
--summary "jira-cli smoke ${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}" \
84+
--description "Automated sandbox smoke test from GitHub Actions.")
85+
ISSUE_KEY=$(jq -r '.data.key // empty' <<<"$CREATE_JSON")
86+
if [ -z "$ISSUE_KEY" ]; then
87+
echo "::error::Issue create did not return a key."
88+
echo "$CREATE_JSON"
89+
exit 1
90+
fi
91+
92+
"${JIRA[@]}" issue view "$ISSUE_KEY"
93+
"${JIRA[@]}" issue edit "$ISSUE_KEY" --label jira-cli-smoke
94+
"${JIRA[@]}" issue list --jql "key = $ISSUE_KEY" --max 1
95+
"${JIRA[@]}" bulk comment "$ISSUE_KEY" --body "Bulk dry-run from run ${GITHUB_RUN_ID}." --dry-run
96+
"${JIRA[@]}" bulk comment "$ISSUE_KEY" --body "Bulk smoke comment from run ${GITHUB_RUN_ID}."
97+
COMMENT_JSON=$("${JIRA[@]}" comment add "$ISSUE_KEY" --body "Smoke comment from run ${GITHUB_RUN_ID}.")
98+
COMMENT_ID=$(jq -r '.data.id // empty' <<<"$COMMENT_JSON")
99+
if [ -n "$COMMENT_ID" ]; then
100+
"${JIRA[@]}" comment view "$ISSUE_KEY" "$COMMENT_ID"
101+
"${JIRA[@]}" comment update "$ISSUE_KEY" "$COMMENT_ID" --body "Updated smoke comment."
102+
fi
103+
104+
"${JIRA[@]}" worklog add "$ISSUE_KEY" --time-spent 1m --comment "Smoke worklog."
105+
"${JIRA[@]}" worklog total "$ISSUE_KEY"
106+
107+
ATTACHMENT="${RUNNER_TEMP}/jira-smoke-attachment.txt"
108+
printf 'jira-cli smoke attachment\n' > "$ATTACHMENT"
109+
"${JIRA[@]}" attachment upload "$ISSUE_KEY" "$ATTACHMENT"
110+
"${JIRA[@]}" attachment list "$ISSUE_KEY"
111+
112+
if [ -n "${JIRA_SMOKE_BOARD_ID:-}" ]; then
113+
"${JIRA[@]}" board view "$JIRA_SMOKE_BOARD_ID"
114+
"${JIRA[@]}" cache refresh boards --project "$JIRA_SMOKE_PROJECT"
115+
"${JIRA[@]}" cache refresh sprints --board "$JIRA_SMOKE_BOARD_ID"
116+
"${JIRA[@]}" sprint list --board "$JIRA_SMOKE_BOARD_ID" --state active || true
117+
"${JIRA[@]}" issue list --jql "project = $JIRA_SMOKE_PROJECT AND @current-sprint" --board "$JIRA_SMOKE_BOARD_ID" --max 1 || true
118+
fi

0 commit comments

Comments
 (0)